在最后的诺曼底登陆战开始之前,盟军与德军的情报部门围绕着最终的登陆地点展开了一场规模空前的情报战。
这场情报战中,盟军的战术是利用那些潜伏在敌军内部的双重间谍,将假的登陆消息发布给敌军的情报机关的负责人。那些已经潜入敌后的间谍们都是盟军情报部的
精英,忠实可靠;但是如何选择合适的人选,以及最佳的消息传递方法,才能保证假消息能够尽快而且安全准确地传递到德军指挥官们的耳朵里,成了困扰盟军情报
部长的最大问题。他需要你的帮助。
以下是情报部长提供的作战资料:
在敌后一共潜伏着我方最优秀的N(N<=300)名间谍,分别用数字1, 2, …, N编号。在给定的作战时间内,任意两人之间至多只进行一次点对点的双人联系。
我将给你一份表格,表格中将提供任意两位间谍i和j之间进行联系的安全程度,用一个 [0, 1] 的实数Si j表示;以及他们这次联系时,能够互相传递的消息的最大数目,用一个正整数表示Mi j (如果在表格中没有被提及,那么间谍i和j之间不进行直接联系)。
假消息从盟军总部传递到每个间谍手里的渠道也不是绝对安全,我们用 [0, 1]
的实数ASj表示总部与间谍j之间进行联系的安全程度,AMj则表示总部和间谍j之间进行联系时传递的消息的最大数目。对于不和总部直接联系的间谍,他的
AMj=0(而表格中给出的他的ASj是没有意义的)。
当然,假消息从间谍手中交到敌军的情报部官员的办公桌上的过程是绝对安全的,也即是说,间谍与敌军情报部门之间要么不进行直接联系,要么其联系的安全程度是1(即完全可靠)。
现在情报部打算把K条假消息“透露”到德军那里。消息先由总部一次性发给N名间谍中的一些人,再通过他们之间的情报网传播,最终由这N名间谍中的某些将情报送到德军手中。
对于一条消息,只有安全的通过了所有的中转过程到达敌军情报部,这个传递消息的过程才算是安全的;因此根据乘法原理,它的安全程度P就是从总部出发,经多次传递直到到达德军那里,每一次传递该消息的安全程度的乘积。
而对于整个计划而言,只有当N条消息都安全的通过情报网到达德军手中,没有一条引起怀疑时,才算是成功的。所以计划的可靠程度是所有消息的安全程度的乘积。
显然,计划的可靠性取决于这些消息在情报网中的传递方法。
我需要一个方案,确定消息应该从哪些人手中传递到哪些人手中,使得最终计划的可靠性最大。
你可以利用计算机,来求得这个最可靠的消息传递方案。
第一行包括两个整数N(N<=300)和K,分别是间谍的总人数和计划包含的消息总数。
第二行包括2N个数,前N个数是实数AS1, AS2, …, ASN(范围在[0, 1]以内);后N个数是整数AM1, AM1, …, AMN。
第三行包含了N个整数,其中第i(i = 1, 2, …, N)个整数如果为0表示间谍i与德军情报部不进行联系,如果为1则表示间谍与德军情报部进行联系。
第四行开始,每行包括4个数,依次分别是:代表间谍编号的正整数i和j,间谍i和j联系的安全性参数Si j([0,1]范围内的实数),以及i、j之间传递的最大消息数 Mi j(每一行的i均小于j )。
最后的一行包含两个整数-1 -1,表示输入数据的结束。
0
只有一行。这一行中包含一个实数P,给出的是整个计划的可靠程度P,保留5位有效数字(四舍五入)。
如果情报网根本不能将K条消息传到德军手中,那么计划的可靠性为0。
(你可以假定,如果计划存在,那么它的可靠性大于1e-12)
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <queue>
5 using namespace std;
6 const int maxn=310;
7 const int maxm=250010;
8 const double eps=1e-12;
9 const int INF=1000000000;
10 int cnt=1,fir[maxn],path[maxn];
11 int n,k,to[maxm],nxt[maxm],cap[maxm];
12
13 long double val[maxm],dis[maxn];
14
15 void addedge(int a,int b,int c,double v){
16 nxt[++cnt]=fir[a];
17 fir[a]=cnt;
18 cap[cnt]=c;
19 val[cnt]=v;
20 to[cnt]=b;
21 }
22
23 queue<int>q;
24 int vis[maxn];
25 long double BFS(int S,int T){
26 vis[S]=1;q.push(S);
27 for(int i=S+1;i<=T;i++)
28 dis[i]=0;dis[S]=1;
29 while(!q.empty()){
30 int x=q.front();q.pop();vis[x]=0;
31 for(int i=fir[x];i;i=nxt[i])
32 if(cap[i]&&eps<dis[x]*val[i]-dis[to[i]]){
33 dis[to[i]]=dis[x]*val[i];
34 if(!vis[to[i]])q.push(to[i]);
35 vis[to[i]]=1;path[to[i]]=i;
36 }
37 }
38 return dis[T];
39 }
40
41 int Aug(int S,int T){
42 int f=INF,p=T;
43 while(p!=S){
44 f=min(f,cap[path[p]]);
45 p=to[path[p]^1];
46 }
47 p=T;
48 while(p!=S){
49 cap[path[p]]-=f;
50 cap[path[p]^1]+=f;
51 p=to[path[p]^1];
52 }
53 return f;
54 }
55
56 long double MCMF(int S,int T){
57 int f,totf=0;
58 long double ret=1.0,d;
59 while((d=BFS(S,T))>eps){
60 f=Aug(S,T);totf+=f;
61 while(f--)ret*=d;
62 }
63 return totf==k?ret:0.0;
64 }
65
66 void Print(long double ans){
67 char s[50];
68 sprintf(s,"%.15Lf\n",ans);
69 int p=0,tot=0;
70 while(tot<5){
71 if(s[p]!=‘0‘&&s[p]!=‘.‘||tot)
72 tot+=1;
73 p++;
74 }
75 if(s[p]>=‘5‘)s[p-1]+=1;
76 s[p]=‘\000‘;printf("%s",s);
77 }
78
79 int C[maxn];
80 long double P[maxn];
81 int main(){
82 #ifndef ONLINE_JUDGE
83 freopen("agent.in","r",stdin);
84 freopen("agent.out","w",stdout);
85 #endif
86 scanf("%d%d",&n,&k);
87 for(int i=1;i<=n;i++)scanf("%Lf",&P[i]);
88 for(int i=1;i<=n;i++)scanf("%d",&C[i]);
89
90 for(int i=1;i<=n;i++){
91 if(C[i]>0&&P[i]>eps){
92 addedge(n+1,i,C[i],P[i]);
93 addedge(i,n+1,0,1/P[i]);
94 }
95 }
96 for(int i=1,c;i<=n;i++){
97 scanf("%d",&c);
98 if(c>0){
99 addedge(i,n+2,INF,1);
100 addedge(n+2,i,0,1);
101 }
102 }
103
104 int a,b,c;
105 long double p;
106 while(true){
107 scanf("%d%d",&a,&b);
108 if(a==-1&&b==-1)break;
109 scanf("%Lf%d",&p,&c);
110 addedge(a,b,c,p);
111 addedge(b,a,0,1/p);
112 addedge(b,a,c,p);
113 addedge(a,b,0,1/p);
114 }
115 addedge(0,n+1,k,1);
116 addedge(n+1,0,0,1);
117 long double ans=MCMF(0,n+2);
118 if(ans>eps)Print(ans);
119 else printf("0\n");
120 return 0;
121 }