因为行可以了,那列就不行,所以根据行列建立最小割模型。
然后这题精妙之处在于把乘法取对数后转化为加法,瞬间就简单了。
保证精度,C++AC ,16MS G++WA。
#include<stdio.h> #include<string.h> #include<queue> #include<math.h> #define maxn 120 #define INF 10000000 using namespace std; struct node { int to; double v; int flag; int next; }edge[2000]; int pre[maxn],index,vis[maxn],n,m,L,st,se; double col[55],row[55]; double min(double x,double y) { return x<y?x:y; } void add(int x,int y,double z) { edge[index].to=y; edge[index].v=z; edge[index].flag=index+1; edge[index].next=pre[x]; pre[x]=index++; edge[index].to=x; edge[index].v=0; edge[index].flag=index-1; edge[index].next=pre[y]; pre[y]=index++; } double dfs(int u,double low) { int i; double used=0; if(u==se)return low; for(i=pre[u];i!=-1;i=edge[i].next) { if(vis[edge[i].to]==vis[u]+1&&edge[i].v>0) { double a=dfs(edge[i].to,min(low-used,edge[i].v)); edge[i].v-=a; edge[edge[i].flag].v+=a; used+=a; if(used-low>1e-7)break; } } if(!used)vis[u]=-1; return used; } int BFS() { int i; queue<int>q; memset(vis,-1,sizeof(vis)); vis[0]=0; q.push(0); while(!q.empty()) { int t=q.front(); q.pop(); for(i=pre[t];i!=-1;i=edge[i].next) { if(vis[edge[i].to]<0&&edge[i].v>0) { vis[edge[i].to]=vis[t]+1; q.push(edge[i].to); } } } return vis[se]!=-1; } void init() { int i; index=1; st=0,se=115; memset(pre,-1,sizeof(pre)); scanf("%d%d%d",&n,&m,&L); for(i=1;i<=n;i++) { scanf("%lf",&row[i]); add(st,i,log(row[i])); } for(i=1;i<=m;i++) { scanf("%lf",&col[i]); add(i+50,se,log(col[i])); } for(i=0;i<L;i++) { int x,y; scanf("%d%d",&x,&y); add(x,50+y,INF*1.0); } } void slove() { double ans=0; while(BFS()) { while(1) { double a=dfs(0,INF*1.0); if(a<1e-7)break; ans+=a; } } printf("%.4lf ",exp(ans)); } int main() { int t; scanf("%d",&t); while(t--) { init(); slove(); } }