poj2516 最小费用最大流

第一次见到这样的题,真的是看别人的思想然后看别人的代码了一晚上,先明白别人的代码的意思,但是不懂为什么那么写,然后画个图忽然就明白了,下面就是根据这道题最初最小费用最大流的分析!

题目大意:给出n个客户对k个商品的需求量,又给出m个仓库对k个物品的存货量以及对k个物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费,是典型的最小费用最大流!

题目解析:可以将k中物品分开求最小然后想加!

建图,对每个仓库是一个结点,每个客户也是一个结点,除此之外再加上s源点和t结束点!

1、s到仓库i的边的权值为仓库i的供给量

2、仓库i到客户j的权值为仓库的供给量

3、客户j到t的权值为客户的需求量

4、还有建立花费图,cost[i][j]代表仓库i到客户j的没一个物品的运费

然后用spfa算法求s到t的最小路径(路径上边的权值不为0),如果到t的最短路径有更新(此条路径话费最少),则记录这条路径,求出这条路径上权值最小的边的权值,然后这条路径上所有的边的权值都减去该边的权值min,此时最小的花费增加了min*在这条边上的花费!如果s到t的值没有更新,则对于k物品的最小花费则已经求出来了!

表达能力不强,脑袋清楚说不出来,下面是代码,如果实在不明白的话就好好看看代码哈!

 

  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<string>  
  4. #include<cmath>  
  5. #include<queue>  
  6. using namespace std;  
  7. #define min(a,b) (a)<(b)?(a):(b)  
  8. #define N 130  
  9. #define inf 100000000  
  10. int need[N][N];  
  11. int offer[N][N];  
  12. int map[N][N],cost[N][N];  
  13. int sum_need[N],sum_offer[N];  
  14. int n,m,K;  
  15. int pre[N];  
  16. int s,t;//源点和结束点  
  17. int spfa()  
  18. {  
  19.     int dis[N];  
  20.     bool vis[N];  
  21.     int i;  
  22.     queue<int>q;  
  23.     for(i=0; i<=t; i++)  
  24.     {  
  25.         vis[i]=false;  
  26.         dis[i]=inf;  
  27.     }  
  28.     vis[s]=true;  
  29.     dis[s]=0;  
  30.     q.push(s);  
  31.     while(!q.empty())  
  32.     {  
  33.         int k=q.front();  
  34.         vis[k]=false;  
  35.         q.pop();  
  36.         for(i=0; i<=t; i++)  
  37.         {  
  38.       
  39.             if(map[k][i] && dis[i]>dis[k]+cost[k][i])  
  40.             {  
  41.                 dis[i]=dis[k]+cost[k][i];  
  42.                 pre[i]=k;  
  43.                 if(vis[i]==false)  
  44.                 {  
  45.                     vis[i]=true;  
  46.                     q.push(i);  
  47.                 }  
  48.             }  
  49.         }  
  50.     }  
  51.     if(dis[t]!=inf)  
  52.         return 1;  
  53.     else  
  54.         return 0;  
  55. }  
  56. int fond()  
  57. {  
  58.     int i,j;  
  59.     int Min=INT_MAX;  
  60.     j=0;  
  61.     while(spfa())  
  62.     {  
  63.         for(i=t;i!=s; i=pre[i])  
  64.             Min=min(Min,map[pre[i]][i]);  
  65.         for(i=t; i!=s; i=pre[i])  
  66.         {  
  67.             map[pre[i]][i]-=Min;  
  68.             map[i][pre[i]]+=Min;  
  69.             j+=cost[pre[i]][i]*Min;  
  70.         }  
  71.     }  
  72.     return j;  
  73. }  
  74. int main()  
  75. {  
  76.     int i,j,k,sum,sign;  
  77.     while(scanf("%d%d%d",&n,&m,&K))  
  78.     {  
  79.         if(n==0 && m==0 && K==0)  
  80.             break;  
  81.         sum=0;  
  82.         memset(sum_need,0,sizeof(sum_need));  
  83.         memset(sum_offer,0,sizeof(sum_offer));  
  84.         for(i=1; i<=n; i++)  
  85.             for(j=1; j<=K; j++)  
  86.             {  
  87.                 scanf("%d",&need[i][j]);  
  88.                 sum_need[j]+=need[i][j];  
  89.             }  
  90.          for(i=1; i<=m; i++)  
  91.            for(j=1; j<=K; j++)  
  92.            {  
  93.                scanf("%d",&offer[i][j]);  
  94.                sum_offer[j]+=offer[i][j];  
  95.            }  
  96.         sign=0;  
  97.         for(i=1; i<=K; i++)  
  98.             if(sum_offer[i]<sum_need[i])  
  99.             {  
  100.                 sign=1;  
  101.                 break;  
  102.             }   
  103.         s=0;  
  104.         t=m+n+1;   
  105.         for(k=1; k<=K; k++)  
  106.         {  
  107.             for(i=0; i<=t; i++)  
  108.                 for(j=0; j<=t; j++)  
  109.                     map[i][j]=cost[i][j]=0;  
  110.             for(i=1+m; i<=n+m; i++)  
  111.                 for(j=1; j<=m; j++)  
  112.                 {  
  113.                     scanf("%d",&cost[j][i]);  
  114.                     cost[i][j]=-cost[j][i];  
  115.                 }   
  116.             if(sign==1)  
  117.                continue;    
  118.             for(i=1; i<=m; i++)  
  119.                map[s][i]=offer[i][k];  
  120.             for(i=1; i<=m; i++)  
  121.                for(j=1+m; j<=n+m; j++)  
  122.                  map[i][j]=offer[i][k];    
  123.            for(i=m+1; i<=m+n; i++)  
  124.                 map[i][t]=need[i-m][k];  
  125.           sum+=fond();  
  126.         }  
  127.     if(sign==1)  
  128.         printf("-1\n");  
  129.     else  
  130.         printf("%d\n",sum);  
  131.     }  
  132.       
  133.     return 0;  
  134. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值