您的位置:首页 > 其它

POJ 2516 Minimum Cost(最小费用最大流)

2014-08-21 11:31 441 查看
题目链接:http://poj.org/problem?id=2516

拆点不行,就拆网。。。。。

题意:有N个店,M个供货商,K种商品。已知供货商的仓库里每种商品的数量以及每种商品运送到每个店的费用,每个店铺对各种商品的需求数量,求最少花费。 

Input 


第一行:N,M,K。

然后1 - N行,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件。

然后 N+1 - M行  ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件。

然后是K个矩阵  ,每个N行M列,第ji个矩阵的第i行第j列代表着第j个供货商给第i个店铺发第ji种货物一件需要的费用。哎哟,我日。。。。


坑题一道啊,感觉已经不是在考查网络流,而是在考察对 繁琐数据输入 的Debug能力,弄了一上午,坑我啊。。。

思路一开始思路就是错的,上去就拆点,将供货商和店铺对应着K种商品,把每个供货商拆成K个,店铺拆成K个,写了一半感觉不对劲,50*50 + 50*50 + 50,肯定超时。

    既然拆点不行,那么就拆网呗。。。把对应所有商品的整个网络,拆成K个单种商品的网络,求出单个商品的子网络的最小费用,最后进行累加就是整个网络的最小费用

建图:

增设两个点,源点s = 0,汇点t = N+M+1,源点与供货商相连,费用0,容量为当前单种商品的供给量

供货商与店铺相连费用已知,容量为正无穷。

店铺与汇点相连,费用0,容量为当前单种商品的需求。

AC代码。。。

552 KB407 msC++
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
const int maxn = 110;
const int maxm = 10000;
const int inf = 1e8;
#define MIN INT_MIN
#define MAX 1e6
#define LL long long
#define init(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i = a;i<b;i++)
#define max(a,b) (a>b)?(a):(b)
#define min(a,b) (a>b)?(b):(a)
using namespace std;
struct node
{
int u,v,w,cap,next;
}edge[maxm];
int pre[maxn],dis[maxn],head[maxn],cnt;
bool vis[maxn];
int n,m;
void add(int u,int v,int c,int cap)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=c;
edge[cnt].cap=cap;
edge[cnt].next=head[u];
head[u]=cnt++;

edge[cnt].u=v;
edge[cnt].v=u;
edge[cnt].w=-c;
edge[cnt].cap=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int spfa(int s,int t)
{
queue<int>q;
while(q.empty()==false) q.pop();
q.push(s);
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
FOR(i,s,t+1)
dis[i] = inf;
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u] = 0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].cap && dis[edge[i].v]>dis[u]+edge[i].w)
{
dis[edge[i].v]=dis[u]+edge[i].w;
pre[edge[i].v] = i;
if(!vis[edge[i].v])
{
vis[edge[i].v]=1;
q.push(edge[i].v);
}
}
}

}
if(dis[t] != inf)
return 1;
else
return 0;
}
int MinCostMaxFlow(int s,int t)
{
int flow=0,cost=0;
while(spfa(s,t))
{
int df = inf;
for(int i = pre[t];i!=-1;i=pre[edge[i].u])
{
if(edge[i].cap<df)
df = edge[i].cap;
}
flow += df;
for(int i=pre[t];i!=-1;i=pre[edge[i].u])
{
edge[i].cap -= df;
edge[i^1].cap += df;
}
cost += dis[t] * df;
}
return cost;
}
void initt()
{
cnt=0;
memset(head,-1,sizeof(head));
}

int main()
{
int gong[51],qiu[51];
int k,s,t;
int need[200][200],gei[200][200];
while(scanf("%d%d%d",&n,&m,&k),n,m,k)
{
init(need);init(gei);
init(gong);init(qiu);
s = 0,t = n+m+1;
FOR(i,1,n+1)
{
FOR(j,1,k+1)
{
scanf("%d",&need[i][j]);
qiu[j] += need[i][j];
}
}
FOR(i,1,m+1)
{
FOR(j,1,k+1)
{
scanf("%d",&gei[i][j]);
gong[j] += gei[i][j];
}
}
bool flag = 1;
FOR(i,1,k+1)
{
if(gong[i]<qiu[i])//如果单种商品的供给量不满足该商品的需求量,直接打印-1
{
flag = 0;
break;
}
}
int cost,yao,money = 0;

FOR(ji,1,k+1)
{
initt();

FOR(i,1,n+1)
{
FOR(j,1,m+1)
{
scanf("%d",&cost);
if(flag==0) continue;
add(j,m+i,cost,inf);//供给商和店主的流量为正无穷
}
}
if(flag==0) continue;
FOR(i,1,n+1)
{
add(m+i,t,0,need[i][ji]);//店铺和汇点的费用为0,流量为店对该种商品的需求
}
FOR(i,1,m+1)
{
add(s,i,0,gei[i][ji]);//源点对供应商的费用为0,流量为供货商对该种商品的供给
}
money += MinCostMaxFlow(s,t);
}
(flag==0)?puts("-1"):printf("%d\n",money);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: