POJ 2516 Minimum Cost

第一道费用流的题目,看了别人博客大概学会了这种算法,就是问如果现在流量也是有单位费用的,如何最大流且有最小费用? 解法是一种贪心,不停地去找费用最小的最短路,最后到无法增广时得到最小费用最大流。这题我用的邻接矩阵,注意题目的图必须分成K个去做,稍微有点复杂,但是基本是模版题,我的建图原则是源点与供应商的最大流量是它能提供的商品,供应商与商店流量无限大,商店与汇点的最大流量是它需要的商品个数(比较复杂,从9点一直做到了11点半 一直在DEBUG的路上狂奔)

code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MAXN 150
#define INF 9999999
using namespace std;
int N, M, K;
int E[MAXN][MAXN], supply[MAXN][MAXN],shop[MAXN][MAXN],G[MAXN][MAXN],cost[MAXN][MAXN][MAXN];
int vis[MAXN], d[MAXN], pre[MAXN], a[MAXN];
void build(int cnt)
{
 memset(E,0,sizeof(E));
 memset(G,0,sizeof(G));
 int i, j, k;
 for(i=1;i<=M;i++)
 {
  E[0][i]=supply[i][cnt];
 }
 for(i=1;i<=N;i++)
 {
  E[i+M][105]=shop[i][cnt];
 }
 for(i=1;i<=M;i++)
 {
  for(j=1;j<=N;j++)
  {
   E[i][j+M]=INF;
   G[i][j+M]=cost[cnt][j][i];
  // G[j+M][i]=cost[cnt][j][i];
  }
 }
}
bool spfa(int s,int t,int& flow,int& cost)
{
 for(int i=1;i<=105;i++)
 d[i]=INF;
 memset(a,0,sizeof(a));
 memset(vis,0,sizeof(vis));
 memset(pre,0,sizeof(pre));
 d[s]=0;
 vis[s]=1;
 a[s]=INF;
 queue<int> q;
 q.push(s);
 while(!q.empty())
 {
  int x=q.front();
  q.pop();
  vis[x]=0;
 // cout<<"K"<<x<<endl;
  for(int i=1;i<=105;i++)
  {
   if(E[x][i]&&d[i]>d[x]+G[x][i])
   {
    d[i]=d[x]+G[x][i];
    a[i]=min(a[x],E[x][i]);
    pre[i]=x;
    if(!vis[i]){
     q.push(i);
     vis[i]=1;
    }
   }
  }
 }
 if(d[t]==INF)
  return false;
 flow+=a[t];
 cost+=(long long)d[t]*(long long)a[t];
 for(int i=t;i!=s;i=pre[i])
 {
  E[pre[i]][i]-=a[t];
  E[i][pre[i]]+=a[t];
  G[i][pre[i]]=-G[pre[i]][i];
 }
 return true;
}
int main()
{
 int i, j, k;
 while(1)
 {
 cin>>N>>M>>K;
 if(N==0&&M==0&&K==0)
 break;
// memset(E,0,sizeof(E));
// memset(G,0,sizeof(G));
 memset(supply,0,sizeof(supply));
 memset(shop,0,sizeof(shop));
 memset(cost,0,sizeof(cost));
 for(i=1;i<=N;i++)
 {
  for(j=1;j<=K;j++)
  {
   cin>>shop[i][j];
  }
 }
 for(i=1;i<=M;i++)
 {
  for(j=1;j<=K;j++)
  {
   cin>>supply[i][j];
  }
 }
 for(i=1;i<=K;i++)
 {
  for(j=1;j<=N;j++)
  {
   for(k=1;k<=M;k++)
   {
    cin>>cost[i][j][k];
   }
  }
 }
 int cnt=1, ans=0, flag=0;
 int cost=0;
 while(K--)
 {
  build(cnt);
  int flow=0,sum=0;
 // cout<<cnt<<endl;
  while(spfa(0,105,flow,cost));
  for(i=1;i<=N;i++)
  {
   sum+=shop[i][cnt];
  }
  if(flow!=sum)
   flag=1;
  if(flag)
  break;
  cnt++;
 }
 if(!flag)
 cout<<cost<<endl;
 else
 cout<<-1<<endl;
 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值