poj 3308 (最大流 最小点权覆盖)

来源:互联网 发布:淘宝几天自动确认收货? 编辑:程序博客网 时间:2024/05/17 09:17

dinic递归法调了一下午最后TLE。。。

二分图最小点权覆盖:

从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。

行为一个集合,列为一个集合。因为要乘积,所以用对数来算,就变成加法了。也就转换成求最小割。用最大流来做。


#include<stdio.h>#include<string.h>#include<cmath>#include<iostream>#include<queue>#define MX 100000using namespace std;double map[200][200],f[200][200];int d[1000],m,n,l;bool bfs(){queue <int> Q;Q.push(0);memset(d,-1,sizeof(d));d[0]=0;while(!Q.empty()){int v=Q.front();Q.pop();for(int i=0;i<=n+m+1;i++){if(d[i]==-1&&map[v][i]-f[v][i]>0){d[i]=v;Q.push(i);if(i==n+m+1)return true;}}}return false;}double dinic(){double min_flow=0,min_f;while(bfs()){min_f=MX;for(int i=n+m+1,j=d[i];j!=i;){if(map[j][i]-f[j][i]<min_f){min_f=map[j][i]-f[j][i];}i=j;j=d[j];}//printf("!! %lf\n",min_f);for(int i=n+m+1,j=d[i];j!=i;){f[j][i]+=min_f;f[i][j]-=min_f;i=j;j=d[j];}min_flow+=min_f;//printf("! %lf\n",min_flow);}return min_flow;}int main(){int cas;scanf("%d",&cas);while(cas--){memset(map,0,sizeof(map));memset(f,0,sizeof(f));scanf("%d%d%d",&m,&n,&l);for(int i=1;i<=m;i++){double a;scanf("%lf",&a);map[0][i]=log(a);}for(int i=1;i<=n;i++){double a;scanf("%lf",&a);map[i+m][m+n+1]=log(a);}for(int i=1;i<=l;i++){int x,y;scanf("%d%d",&x,&y);map[x][y+m]=MX;}double ans=0;ans=dinic();printf("%.4lf\n",exp(ans));}return 0;}


原创粉丝点击