@zzzc18
2017-05-12T12:05:31.000000Z
字数 3927
阅读 1529
TEST
Lemon 因为偶然的原因,当上了警察局长。而一上任,他就碰到了个大麻烦:追捕周克华。
周克华是人尽皆知的抢劫杀人犯,而就在几天前,他在 Lemon 辖区内的银行门口,枪杀了
一名储户后逃之夭夭。Lemon 知道,如果他抓不住周克华,他的警察局长恐怕就当不下去了。
为了能继续当他的警察局长,Lemon 决定倾警察局之物力全力追捕。Lemon 的辖区可以表示
为一张边上带权的无向图。银行位于结点 1。
Lemon 仔细研究周克华的案底后得出以下结论:
首先,周克华拥有极强的反侦查能力,因此,他深知不走回头路的重要性。他永远不会访问
任何一个结点两次。
其次,周克华深知多走一分钟路就多一分钟暴露的危险,而且他之前已经完全摸清了辖区的
地形,因此他总是走最短路,也就是,他访问任何一个结点时,走的路线都是从银行到这里
的最短路。为了简化题目,我们保证从银行(结点 1)到任何一个结点的最短路都是唯一的。
再次,周克华知道,为了尽可能远离案发现场,他必须不停的运动。也就是说,只要有相邻
的结点能满足“不走回头路、只走最短路”的前提,他一定会移动。如果有多个相邻结点可
供选择,他会随机等概率选择一个作为他的移动目标。如果没有结点满足这一要求,那么周
克华就会选择遁入深山之中,而可以想象在距离案发现场十万八千里的山区里抓捕周克华的
难度,所以一旦周克华遁入山中,也就意味着 Lemon 的抓捕行动失败了。
Lemon 分析出了以上结论后决定,只能在结点上布置警察,实施埋伏抓捕。但是,周克华的
身体素质、反侦查能力和使用武器技术都十分优秀,因此,即使周克华遇到了埋伏,也有一
定几率杀害所有参与埋伏的警察后逃脱。当然,随着埋伏的警察的数目的增多,逃脱几率会
减小。如果逃脱成功,周克华会像什么都没发生一样,继续按上文所述的方式行动。
注意,周克华一旦到达一个结点,埋伏在那里的警察会立即实施抓捕,只有周克华逃脱了在
当前结点的抓捕后才能进行下一步行动(遁入群山或继续移动),包括结点 1,也就是周克
华需要先逃脱结点 1 的埋伏才能走出他的第一步。
Lemon 知道,他的设置警力方式决定了追捕成功的概率。他现在已经知道了他的辖区地图以
及在不同地点设置不同数量的警力能成功抓捕周克华的概率,Lemon 现在想要找到一个尽量
优的方式设置警力,因此求助于你。你能告诉 Lemon 在最优的设置下,抓捕成功概率是多
少吗? Lemon 到时或许会把高额的悬赏分给你一部分的哦~
输入文件第一行包含两个数 N,M,分别表示辖区里的结点数目和边的数目。
接下来 M 行,每行 3 个数 a,b,c,表示结点 a 和 b 之间有一条权值为 c 的无向边。
接下来一个数 S,表示可以参与埋伏的警察个数。
接下来 N 行,每行 S 个数,第 i 行第 j 个数 Pij 表示在结点 i 埋伏 j 个警察抓捕成功的概率。
注意,如果不埋伏任何警察,那么显然绝不可能成功抓住周克华。
输出文件仅包含一个实数,保留到 4 位小数,表示在最优警力设置下,抓捕成功的概率。
4 4
1 2 1
1 3 2
2 4 3
3 4 1
2
0.01 0.1
0.5 0.8
0.5 0.8
0.7 0.9
0.6000
//最开始把每个点的概率算出来再一块01背包,显然不对,然而还是过了一个点.....
正解:
Step1:预处理出从1为起点的最短路,构建一个新图,只包含最短路(因为他非最短路不走嘛)
Step2:树形DP,在DP时每个节点以其子节点为物品做一次01背包
ans:total answer;dp:single dot answer;tmp:bags for sonsfor(i=h1[x];i;i=e1[i].next){for(j=0;j<=police;j++) tmp[j]=0;for(j=0;j<=police;j++){for(k=0;k<=j;k++){tmp[j]=max(tmp[j],dp[j-k]+ans[e1[i].to][k]);}}for(j=0;j<=police;j++)dp[j]=max(dp[j],tmp[j]);}
Step3:DP的同时把概率考虑进去(size为当前节点的子节点数)
for(i=0;i<=police;i++)dp[i]/=size[x];for(i=0;i<=police;i++){for(j=0;j<=i;j++){ans[x][i]=max(ans[x][i],dp[i-j]+(1-dp[i-j])*node[x].num[j]);}}
#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#define MAXM 20005#define MAXN 205using namespace std;int n,m,edge_num,e_num;int police;struct E{int next,to,val;}edge[MAXM*2],e1[2*MAXM];int dis[MAXN];queue<int> que;bool inque[MAXN];int head[MAXN],h1[MAXN];struct N{double num[MAXN];double ZH;}node[MAXN];int size[MAXN];double ans[MAXN][MAXN],dp[MAXN],tmp[MAXN];void addedge(int x,int y,int z){edge[++edge_num].next=head[x];edge[edge_num].to=y;edge[edge_num].val=z;head[x]=edge_num;}void add(int x,int y,int z){e1[++e_num].next=h1[x];e1[e_num].to=y;e1[e_num].val=z;h1[x]=e_num;}void SPFA(){memset(dis,0x7f,sizeof(dis));dis[1]=0;que.push(1);while(!que.empty()){int fro=que.front();que.pop();inque[fro]=0;int i;for(i=head[fro];i;i=edge[i].next){if(dis[edge[i].to]>dis[fro]+edge[i].val){dis[edge[i].to]=dis[fro]+edge[i].val;if(!inque[edge[i].to]){inque[edge[i].to]=1;que.push(edge[i].to);}}}}}void newmap(int x,int fa){int i;for(i=head[x];i;i=edge[i].next){if(edge[i].to==fa) continue;if(dis[x]+edge[i].val==dis[edge[i].to]){add(x,edge[i].to,edge[i].val);newmap(edge[i].to,x);}}}void DFS(int x,int fa){int i;for(i=h1[x];i;i=e1[i].next){size[x]++;DFS(e1[i].to,x);}}void DP(int x){int i,j,k;if(!size[x]){for(i=0;i<=police;i++)ans[x][i]=node[x].num[i];return;}for(i=h1[x];i;i=e1[i].next) DP(e1[i].to);for(int u=0;u<=police;u++)dp[u]=0;for(i=h1[x];i;i=e1[i].next){for(j=0;j<=police;j++) tmp[j]=0;for(j=0;j<=police;j++){for(k=0;k<=j;k++){tmp[j]=max(tmp[j],dp[j-k]+ans[e1[i].to][k]);}}for(j=0;j<=police;j++)dp[j]=max(dp[j],tmp[j]);}for(i=0;i<=police;i++)dp[i]/=size[x];for(i=0;i<=police;i++){for(j=0;j<=i;j++){ans[x][i]=max(ans[x][i],dp[i-j]+(1-dp[i-j])*node[x].num[j]);}}}void solve(){newmap(1,0);DFS(1,0);DP(1);double ANS=0;for(int i=0;i<=police;i++){ANS=max(ANS,ans[1][i]);}printf("%.4lf\n",ANS);}int main(){freopen("catch.in","r",stdin);freopen("catch.out","w",stdout);scanf("%d%d",&n,&m);int i;int a,b,c;for(i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&c);addedge(a,b,c);addedge(b,a,c);}scanf("%d",&police);int j;for(i=1;i<=n;i++){for(j=1;j<=police;j++){scanf("%lf",&node[i].num[j]);}}SPFA();solve();return 0;}