Minimum Cost(最小费用最大流)

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\n",total);
153         else
154             printf("-1\n");
155     }
156     return 0;
157 }
View Code

 

       

 

posted @ 2013-12-19 11:41  N_ll  阅读(236)  评论(0)    收藏  举报