ACM: K次最小费用最大流 图论题 po…

来源:互联网 发布:杭州创业软件官网 编辑:程序博客网 时间:2024/05/27 02:28

                                                            Minimum Cost

Description

Dearboy, a goods victualer, now comes to a big problem, and heneeds your help. In his sale area there are N shopkeepers (markedfrom 1 to N) which stocks goods from him.Dearboy has M supplyplaces (marked from 1 to M), each provides K different kinds ofgoods (marked from 1 to K). Once shopkeepers order goods, Dearboyshould arrange which supply place provide how much amount of goodsto shopkeepers to cut down the total cost of transport.

It's known that the cost to transport one unit goods for differentkinds from different supply places to different shopkeepers may bedifferent. Given each supply places' storage of K kinds of goods, Nshopkeepers' order of K kinds of goods and the cost to transportgoods for different kinds from different supply places to differentshopkeepers, you should tell how to arrange the goods supply tominimize the total cost of transport.

Input

The input consists of multiple test cases. The first line ofeach test case contains three integers N, M, K (0 <N, M, K < 50), which are described above. The next Nlines give the shopkeepers' orders, with each line containing Kintegers (there integers are belong to [0, 3]), which representsthe amount of goods each shopkeeper needs. The next M lines givethe supply places' storage, with each line containing K integers(there integers are also belong to [0, 3]), which represents theamount of goods stored in that supply place.

Then come K integer matrices (each with the size N * M), theinteger (this integer is belong to (0, 100)) at the i-th row, j-thcolumn in the k-th matrix represents the cost to transport one unitof k-th goods from the j-th supply place to the i-thshopkeeper.

The input is terminated with three "0"s. This test case should notbe processed.

Output

For each test case, if Dearboy can satisfy all the needs of allthe shopkeepers, print in one line an integer, which is the minimumcost; otherwise just output "-1".

Sample Input

1 3 3

1 1 1

0 1 1

1 2 2

1 0 1

1 2 3

1 1 1

2 1 1

 

1 1 1

3

2

20

 

0 0 0

Sample Output

4

-1

 

题意: K中商品都要求出最小费用最大流.

 

解题思路:

               1. 每种商品都是独立的, 建图K次求K次最小费用最大流.

               2. 难点是每次建图.

               3. KM算法参考刘汝佳代码.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define MAX 105
const int INF = (1<<30);

int n, k, m;
int cost[51][51][51], store[51][51];
int flow[MAX][MAX];
int cap[MAX][MAX];
int p[MAX];
int b[MAX][MAX];
int order[51][51];
int dist[MAX];
bool vis[MAX];
int start, end;

inline int min(int a,int b)
{
    return a< b ? a : b;
}

void read_graph()
{
    for(int i =1; i <= n; ++i)
    {
      for(int j = 1; j <= k; ++j)
         scanf("%d",&order[i][j]);
    }
    
   for(int  i = 1; i<= m; ++i)
    {
      for(int j = 1; j <= k; ++j)
         scanf("%d",&store[i][j]);
    }
    
    for(int i =1; i <= k; ++i)
    {
      for(int j = 1; j <= n; ++j)
      {
         for(int kk = 1; kk <= m;++kk)
            scanf("%d",&cost[i][kk][j]);
      }
    }
    start =0;
    end =m+n+1;
}

bool spfa()
{
   memset(p,-1,sizeof(p));
   memset(vis,false,sizeof(vis));
    vis[start] =true;
   queue<int>qu;
   qu.push(start);
    for(int i=1; i <= n+m+1; ++i)
      dist[i] = (i == start ? 0 : INF);
    
    while(!qu.empty() )
    {
      int u = qu.front();
      qu.pop();
      vis[u] = false;
      for(int v = 0; v <= n+m+1;++v)
      {
         if(cap[u][v] > flow[u][v]&& dist[v] > dist[u]+ b[u][v])
         {
            dist[v] = dist[u] + b[u][v];
            p[v] = u;
            if(!vis[v])
            {
               qu.push(v);
               vis[v] = true;
            }
         }
      }
    }
    if(dist[end]>= INF)
      return false;
    else
      return true;
}

int solve()
{
    intminflow;
   while(true)
    {
      if( !spfa() )
         break;
      minflow = INF;
      
      for(int u = end; u != start; u = p[u])
      {
         minflow = min(minflow,cap[p[u]][u] -flow[p[u]][u]);
      }
      
      for(int u = end; u != start; u = p[u])
      {
         flow[p[u]][u] += minflow;
         flow[u][p[u]] -= minflow;
      }
    }
}

int main()
{
//   freopen("input.txt","r",stdin);
   while(scanf("%d %d%d",&n,&m,&k) !=EOF && (n!=0&& m != 0&& k != 0))
    {
      read_graph();
      int result = 0;
      bool flag = true;
      for(int i = 1; i <= k;++i)  //每种商品是独立的.
      {
      //   creat_graph();
         memset(cap,0,sizeof(cap));
         memset(b,0,sizeof(b));
         memset(flow,0,sizeof(flow));
         for(int j = 1; j <= m;++j)  //超级源点到提供者建弧
            cap[start][j] = store[j][i];
         for(int j = 1; j <= m; ++j)
         {
            for(int kk = 1; kk <= n;++kk)
               cap[j][kk+m] = store[j][i];
         }
         for(int j =1; j <= n;++j)  //提供者到购买者
            cap[j+m][end] = order[j][i];
         for(int j = 1; j <= m; ++j)
         {
            for(int kk = 1; kk <= n;++kk)
            {
               b[j][kk+m] = cost[i][j][kk];
               b[kk+m][j] = -b[j][kk+m]; //回流减少费用
            }
         }
         solve();
         
         for(int j = 1; j <= n; ++j)
         {
            if(cap[j+m][end] != flow[j+m][end])
            {
               flag = false;
               break;
            }
         }
         if(!flag) break;
         for(int j = 1; j <= m; ++j)
         {
            for(int kk = 1; kk <= n;++kk)
               result += flow[j][m+kk] * b[j][m+kk];
         }
      }
      if(flag)
         printf("%d\n",result);
      else
         printf("-1\n");
    }
    return0;
}

 

0 0
原创粉丝点击