题目链接
https://vjudge.net/problem/POJ-2516
题意
n个店铺,从m个市场进货,k种货物。给定市场k种货物存量,店铺k种货物需求,运输花费,问是否能满足要求,最小花费是多少
思路
费用流没得跑,就看如何建图
我一开始是一次性建图,出现以下几个问题
- 点编号太难了,一一对应很费脑子
- 边太多了,MCMF超时
看别的博客知道了要拆成k张图,对k种货物一一处理。因为我们需要满足所有需求,也就是必须满流,所以可以独立得拆成k张图,拆了之后发现建图简单了一个量级,按部就班建图就可以了
数据
来源POJ讨论区,感谢前辈们提供数据
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
2 4 3
0 2 3
2 3 4
1 0 2
1 0 3
0 2 4
2 3 0
2 3 1 2
1 2 3 1
1 1 2 3
2 1 3 1
2 2 3 1
2 3 4 1
2 2 1
1 1 1 1
1 2 2 100
2 4 5
2 1 2 2 2
1 1 1 2 1
2 2 2 2 2
2 1 2 1 1
2 2 2 2 1
1 2 2 2 1
1 1 6 7
5 5 2 9
4 6 6 9
9 1 9 1
7 4 1 7
4 4 7 3
5 4 7 7
9 1 3 8
8 8 2 7
1 4 7 1
1 2 3
1 1 2
2 2 1
2 1 1
7 4
4 1
7 3
0 0 0
output:
4
-1
27
4
38
15
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
typedef long long ll;
const int maxn=55*55;
const int maxe=500005;
const int inf=0x3f3f3f3f;
int n,m,k,s,t,cnt;
int head[maxn];
struct Edge{
int v,w,next,flow;
}edge[maxe];
int dis[maxn],incf[maxn],pre[maxn];//incf最小流量
bool inque[maxn];
int maxflow,mincost;
//费用流模版
void init(){
memset(head,-1,sizeof(head));
maxflow=mincost=0;
cnt=0;
}
void add(int u,int v,int flow,int cost){
//cout<<u<<" "<<v<<" "<<flow<<" "<<cost<<endl;
edge[cnt].w=cost;
edge[cnt].v=v;
edge[cnt].flow=flow;
edge[cnt].next=head[u];
head[u]=cnt++;
return ;
}
bool spfa(){
queue<int>q;
memset(dis,0x3f,sizeof(dis));
memset(inque,0,sizeof(inque));
q.push(s); dis[s]=0; inque[s]=1; incf[s]=inf;
while(q.size()){
int u=q.front();q.pop();
inque[u]=0;
for(int i=head[u];~i;i=edge[i].next){
if(!edge[i].flow) continue;
int v=edge[i].v;
if(dis[v]>dis[u]+edge[i].w){
dis[v]=dis[u]+edge[i].w;
incf[v]=min(incf[u],edge[i].flow);
pre[v]=i;
if(!inque[v]){
q.push(v);
inque[v]=1;
}
}
}
}
if(dis[t]==inf) return 0;
return 1;
}
void MCMF(){
while(spfa()){
int x=t;
maxflow+=incf[t];
mincost+=dis[t]*incf[t];
int i;
while(x!=s){
i=pre[x];
edge[i].flow-=incf[t];
edge[i^1].flow+=incf[t];
x=edge[i^1].v;
}
}
}
int dian[55][55];//dian i j i店j货物所需
int ku[55][55];//ku i j i库j货物拥有
int val[55][55][55];//val w i j w货物从j库到i店所需
signed main(){
while(scanf("%d%d%d",&n,&m,&k)==3){
int ans=0;
if(!n&&!m&&!k)
break;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
scanf("%d",&dian[i][j]);
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=k;j++)
scanf("%d",&ku[i][j]);
}
for(int w=1;w<=k;w++){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&val[w][i][j]);
}
for(int _=1;_<=k;_++){
int need=0;
init();
s=n*m+1000,t=s+1;
//向汇点连边
for(int i=1;i<=n;i++){
need+=dian[i][_];
add(i,t,dian[i][_],0);
add(t,i,0,0);
}
//源点连边
for(int i=1;i<=m;i++){
add(s,i+n,ku[i][_],0);
add(i+n,s,0,0);
}
//市场-店面
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
add(n+j,i,ku[j][_],val[_][i][j]);
add(i,n+j,0,-val[_][i][j]);
}
}
MCMF();
if(maxflow!=need){
//满足不了
ans=-1;
break;
}
else
ans+=mincost;
}
printf("%d\n",ans);
}
}