http://poj.org/problem?id=3308
题意:一个m*n的网格,有L位火星空降兵降落在网格中,地球卫士为了能同时消灭他们,在网格的行或列安装了一个枪支,每行或每列的枪支都能消灭这一整行或整列的空降兵,给出每一行和每一列安装枪支的花费,总的花费等于所有安装枪支的行和列的花费的乘积。求出最小的总的花费。
思路:(1)最小割:对于图中的两个点(一般为源点和汇点)来说,如果把图中的一些边去掉,如果它们之间无法连通的话,则这些边组成的集合就叫为割了。如果这些边有权值,最小割就是指权值之和最小的一个割。(2)对任意一个只有一个源点和一个汇点的图来说,从源点到汇点的最大流等于最小割,可以用Dinic算法求。由于总的花费等于各花费的乘积,取对数后就能变成和的形式了.
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <queue> 5 #include <math.h> 6 using namespace std; 7 const int N=2525; 8 const double eps=1e-8; 9 const int INF=1<<28; 10 11 struct node 12 { 13 int v,u,next; 14 double w; 15 } edge[N*2]; 16 int head[N],d[N]; 17 int cnt,S,T; 18 void init() 19 { 20 memset(head,-1,sizeof(head)); 21 cnt = 0; 22 } 23 void add(int u,int v,double w) 24 { 25 edge[cnt].u = u; 26 edge[cnt].v = v; 27 edge[cnt].w = w; 28 edge[cnt].next = head[u]; 29 head[u]=cnt++; 30 edge[cnt].u = v; 31 edge[cnt].v = u; 32 edge[cnt].w = 0; 33 edge[cnt].next = head[v]; 34 head[v]=cnt++; 35 } 36 int bfs() 37 { 38 queue<int>q; 39 q.push(S); 40 memset(d,-1,sizeof(d)); 41 d[S] = 0; 42 while(!q.empty()) 43 { 44 int t = q.front(); 45 q.pop(); 46 for (int j = head[t]; j!=-1; j=edge[j].next) 47 { 48 int v = edge[j].v; 49 if (d[v]==-1&&edge[j].w>eps) 50 { 51 d[v] = d[t]+1; 52 q.push(v); 53 } 54 } 55 } 56 if (d[T]>0) 57 return 1; 58 return 0; 59 } 60 double dinic(int t,double sum) 61 { 62 63 if(t==T) 64 return sum; 65 66 67 for (int i = head[t]; i!=-1; i=edge[i].next) 68 { 69 double a; 70 int v = edge[i].v; 71 double w = edge[i].w; 72 if (d[v]==d[t]+1&&w>eps&&(a=dinic(v,min(sum,w)))) 73 { 74 75 edge[i].w-=a; 76 edge[i^1].w+=a; 77 return a; 78 } 79 } 80 return 0; 81 } 82 int main() 83 { 84 int t,m,n,l; 85 int u,v; 86 double val; 87 scanf("%d",&t); 88 while(t--) 89 { 90 init(); 91 scanf("%d%d%d",&m,&n,&l); 92 S = 0; 93 T=n+m+1; 94 for (int i = 1; i <= m; i++) 95 { 96 scanf("%lf",&val); 97 add(S,i,log(val)); 98 } 99 for (int i = 1; i <= n; i++) 100 { 101 scanf("%lf",&val); 102 add(m+i,T,log(val)); 103 } 104 while(l--) 105 { 106 scanf("%d%d",&u,&v); 107 add(u,v+m,INF); 108 } 109 double ans = 0; 110 while(bfs()) 111 { 112 double ss = dinic(S,INF); 113 if(ss>eps) 114 ans+=ss; 115 else break; 116 117 } 118 printf("%.4f ",exp(ans)); 119 } 120 return 0; 121 }