题解 变异大老鼠
作者:互联网
大水题,spt上直接背包即可,但我因为太弱爆零了
- 树上背包当出现在每个点有概率终止DP(举个例子:从点1逃跑,在每个点有概率被抓捕)的情况时:
特别注意在当前节点的容量与字节点的容量是独立的,不能像子树合并一样直接把当前节点的dp值揉进去
否则无法正确统计从当前节点进入下层节点的概率
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define db double
#define fir first
#define sec second
#define make make_pair
//#define int long long
int n, m, k;
int back[N], cnt[N];
ll dis[N];
db p[310][310];
bool vis[N];
priority_queue<pair<ll, int>> q;
namespace edge1{
int head[N], size;
struct edge{int to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {e[++size].to=t; e[size].val=w; e[size].next=head[s]; head[s]=size;}
}
namespace edge2{
int head[N], size;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
}
void init() {
using namespace edge1;
memset(dis, 0x3f, sizeof(dis));
dis[1]=0;
q.push(make(0, 1));
pair<ll, int> u;
while (q.size()) {
u=q.top(); q.pop();
if (vis[u.sec]) continue;
vis[u.sec]=1;
for (int i=head[u.sec],v; ~i; i=e[i].next) {
v = e[i].to;
if (dis[u.sec]+e[i].val < dis[v]) {
dis[v]=dis[u.sec]+e[i].val; back[v]=u.sec;
q.push(make(-dis[v], v));
}
}
}
for (int i=2; i<=n; ++i) edge2::add(back[i], i), ++cnt[back[i]];
}
namespace force{
int num[N];
db ans;
db dfs2(int u) {
using namespace edge2;
db sum=p[u][num[u]];
db ps=1.0/cnt[u];
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
sum+=ps*dfs2(v);
}
return sum;
}
void dfs1(int u, int rest) {
if (u>n) {
if (rest==0) ans=max(ans, dfs2(1));
return ;
}
for (int i=0; i<=rest; ++i) {
num[u]=i;
dfs1(u+1, rest-i);
}
}
void solve() {
dfs1(1, k);
printf("%.6lf\n", min(ans, 1.0));
exit(0);
}
}
namespace task1{
db dp[310][30010], tem[310][30010];
void dfs(int u) {
using namespace edge2;
// cout<<"dfs: "<<u<<' '<<cnt[u]<<endl;
for (int i=1; i<=k; ++i) dp[u][i]=p[u][i];
db ps=cnt[u]?(1.0/cnt[u]):1.0;
// cout<<"ps: "<<u<<' '<<ps<<endl;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
dfs(v);
for (int s=k; ~s; --s) {
for (int t=k-s; ~t; --t) {
tem[u][s+t]=max(tem[u][s+t], tem[u][s]+ps*dp[v][t]);
}
}
}
for (int s=k; ~s; --s) {
for (int t=k-s; ~t; --t) {
dp[u][s+t]=max(dp[u][s+t], dp[u][s]+(1-dp[u][s])*tem[u][t]);
}
}
}
void solve() {
dfs(1);
printf("%.6lf\n", min(dp[1][k], 1.0));
// cout<<"---dp---"<<endl;
// for (int i=1; i<=n; ++i) {for (int j=1; j<=k; ++j) printf("%.3lf ", dp[i][j]); cout<<endl;}
exit(0);
}
}
signed main()
{
freopen("arrest.in", "r", stdin);
freopen("arrest.out", "w", stdout);
using namespace edge1;
memset(edge1::head, -1, sizeof(edge1::head));
memset(edge2::head, -1, sizeof(edge2::head));
scanf("%d%d%d", &n, &m, &k);
for (int i=1,x,y,z; i<=m; ++i) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z); add(y, x, z);
}
for (int i=1; i<=n; ++i) for (int j=1; j<=k; ++j) scanf("%lf", &p[i][j]);
init();
task1::solve();
return 0;
}
标签:老鼠,变异,题解,long,int,sec,dis,节点,define 来源: https://www.cnblogs.com/narration/p/15376810.html