http://poj.org/problem?id=2516
题意:N位店主,M个供应商品的地方,每个地方能供应K种商品,不同地方的不同的商品供应给不同的店主有不同的花费,如果这些店主能被供应,输出最小的花费,否则输出-1.
思路:N位店主: 用编号为0~n-1的点表示
M个供应商品的地方:用编号为 m~m+n-1的点表示
m+n 代表超级源点,m+n+1 代表终极汇点
用这些点建图,求最小费用最大流
1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=120; 7 const int maxm=5000; 8 const int INF=1<<28; 9 struct node 10 { 11 int u,v,cap,cost; 12 int next; 13 } edge[maxm+maxm]; 14 int cnt,maxflow; 15 bool vis[maxn]; 16 int head[maxn],dis[maxn],pre[maxn]; 17 int shop[maxn][maxn],sup[maxn][maxn],sum[maxn]; 18 void init() 19 { 20 cnt = 0; 21 memset(head,-1,sizeof(head)); 22 } 23 void add(int u,int v,int cap,int cost)//加双向边 24 { 25 edge[cnt].u = u; 26 edge[cnt].v = v; 27 edge[cnt].cap = cap; 28 edge[cnt].cost = cost; 29 edge[cnt].next = head[u]; 30 head[u] = cnt++; 31 edge[cnt].u = v; 32 edge[cnt].v = u; 33 edge[cnt].cap = 0; 34 edge[cnt].cost = -cost; 35 edge[cnt].next = head[v]; 36 head[v] = cnt++; 37 } 38 int spfa(int s,int t,int n)//求增广路 39 { 40 memset(vis,false,sizeof(vis)); 41 memset(pre,-1,sizeof(pre)); 42 for (int i = 0; i < n; i++) 43 dis[i] = INF; 44 queue<int>q; 45 q.push(s); 46 vis[s] = true; 47 dis[s] = 0; 48 while(!q.empty()) 49 { 50 int u = q.front(); 51 q.pop(); 52 vis[u] = false; 53 for (int j = head[u]; j!=-1; j=edge[j].next) 54 { 55 int v = edge[j].v; 56 int cost = edge[j].cost; 57 if (edge[j].cap && dis[v] > dis[u]+cost) 58 { 59 dis[v] = dis[u]+cost; 60 pre[v]=j;//v的前驱的下标 61 if (!vis[v]) 62 { 63 q.push(v); 64 vis[v] = 1; 65 } 66 } 67 } 68 } 69 if (dis[t]==INF) return 0; 70 return 1;//存在增广路 71 } 72 int min_cost_max_flow(int s,int t,int n) 73 { 74 int flow = 0,mincost=0,minflow; 75 while(spfa(s,t,n)) 76 { 77 minflow = INF+1; 78 for (int i=pre[t]; i!=-1; i=pre[edge[i].u]) 79 { 80 if (edge[i].cap < minflow) 81 minflow = edge[i].cap; 82 } 83 flow+=minflow; 84 for (int i=pre[t]; i!=-1; i=pre[edge[i].u])//修改增广路 85 { 86 edge[i].cap-=minflow; 87 edge[i^1].cap+=minflow; 88 } 89 mincost+=dis[t]*minflow;//最小花费 90 } 91 maxflow = flow;//最大流 92 return mincost; 93 } 94 95 int main() 96 { 97 int n,m,k; 98 while(~scanf("%d %d %d",&n,&m,&k)) 99 { 100 if(n==0&&m==0&&k==0) 101 break; 102 memset(sum,0,sizeof(sum)); 103 for (int i = 0; i < n; i++) 104 { 105 for (int j = 0; j < k; j++) 106 { 107 scanf("%d",&shop[i][j]); 108 sum[j]+=shop[i][j]; 109 } 110 } 111 for (int i = 0; i < m; i++) 112 { 113 for (int j = 0; j < k; j++) 114 { 115 scanf("%d",&sup[i][j]); 116 } 117 } 118 int flag = 1; 119 int total = 0; 120 for (int tt = 0; tt < k; tt++) 121 { 122 init(); 123 int price; 124 for (int i = 0; i < n; i++) 125 { 126 for (int j = 0; j < m; j++) 127 { 128 129 scanf("%d",&price); 130 add(j,m+i,INF,price); 131 } 132 } 133 if (flag==1) 134 { 135 for (int i = 0; i < m; i++) 136 { 137 add(n+m,i,sup[i][tt],0);//增加超级源点 138 } 139 for (int j = 0; j < n; j++) 140 { 141 add(m+j,n+m+1,shop[j][tt],0);//增加终极汇点 142 } 143 int ans = min_cost_max_flow(m+n,m+n+1,m+n+2);//运送第tt种商品的最少花费 144 if (maxflow!=sum[tt]) 145 { 146 flag = 0; 147 } 148 total+=ans; 149 } 150 } 151 if (flag==1) 152 printf("%d ",total); 153 else 154 printf("-1 "); 155 } 156 return 0; 157 }