题目是一个很明显的二分图带权匹配模型,
添加源点到nx建边,ny到汇点建边,(nx,ny)=inf建边,求最小割既得最小点权覆盖。
在本题中由于求的是乘积,所以先全部取log转换为加法,最后再乘方回来。
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define eps 1e-6 #define ll __int64 const int maxn=110; using namespace std; int n,s,t,level[maxn]; double c[maxn][maxn]; bool makelevel() { memset(level,0,sizeof level); level[s]=1; int q[maxn]; int fro=0,iq=0; q[iq++]=s; int i,v; while(fro!=iq) { v=q[fro++]; for(i=0;i<=t;i++) { if(!level[i]&&c[v][i]) { level[i]=level[v]+1; q[iq++]=i; } } } if(!level[t]) return 0; return 1; } double dfs(int now,double maxf) { if(now==t) return maxf; double ret=0; for(int i=0;maxf!=0&&i<=t;i++) { if(c[now][i]&&level[now]+1==level[i]) { double tmp=dfs(i,min(maxf,c[now][i])); c[now][i]-=tmp; c[i][now]+=tmp; ret+=tmp; maxf-=tmp; } } return ret; } double dinic() { double ans=0; while(makelevel()) ans+=dfs(s,10000000); return ans; } int main() { int icy,m,l,i,aa,bb; double a,b; scanf("%d",&icy); while(icy--) { scanf("%d%d%d",&m,&n,&l); s=0;t=n+m+1; memset(c,0,sizeof c); for(i=1;i<=m;i++) { scanf("%lf",&a); c[0][i]=log(a); } for(i=1;i<=n;i++) { scanf("%lf",&a); c[i+m][t]=log(a); } for(i=0;i<l;i++) { scanf("%d%d",&aa,&bb); c[aa][bb+m]=10000000; } printf("%.4lf\n",exp(dinic())); } return 0; }
poj3308 Paratroopers --- 最小点权覆盖->最小割
时间: 2024-11-05 18:10:26