#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
int m,n;
int fst[10005];
int nxt[100005];
int v[100005];
int k[100005];
int d[10005];
int b[10005];
int cst[100005];
int S=10001;
int T=10002;
const int inf=1000000000;
int cost;
queue<int > q;
int getr(int x,int y)
{
return (x-1)*n+y;
}
int getc(int x,int y)
{
return (x-1)*n+y+n*m;
}
int edge=1;
void add(int x,int y,int val,int ct)
{
edge++;
nxt[edge]=fst[x];
fst[x]=edge;
v[edge]=y;
k[edge]=val;
cst[edge]=ct;
}
bool spfa()
{
for(int i=0;i<=n*m*2;i++)
d[i]=-inf,b[i]=0;//初始化
d[T]=-inf;
d[S]=0;
q.push(S);
while(!q.empty())
{
int x=q.front();
q.pop();
b[x]=0;
for(int i=fst[x];i;i=nxt[i])
{
if(k[i]&&d[v[i]]<d[x]+cst[i])//松弛操作
{
d[v[i]]=d[x]+cst[i];
if(!b[v[i]])b[v[i]]=1,q.push(v[i]);
}
}
}
if(d[T]<0)return 0;
return 1;//如果汇点没有被访问到返回0
}
int dfs(int x,int val)
{
if(x==T||!val)
{
cost+=d[T]*val;//本次增广获得的费用
return val;
}
b[x]=1;
int tmp=0;
for(int i=fst[x];i;i=nxt[i])
{
if(!b[v[i]]&&d[v[i]]==d[x]+cst[i]&&k[i])//分层
{
int flow=dfs(v[i],min(val,k[i]));
val-=flow;
k[i]-=flow;
k[i^1]+=flow;
tmp+=flow;
}
if(!val)break;
}
if(!tmp)d[x]=-inf;//阻塞
return tmp;
}
void dinic()
{
while(spfa())
{
dfs(S,inf);
}
}
int main()
{
scanf("%d%d",&m,&n);
int x;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&x);
int rd=getr(i,j);
int cd=getc(i,j);
add(rd,cd,1,x);
add(cd,rd,0,-x);
add(rd,cd,inf,0);
add(cd,rd,0,0);
if(i<m)
{
int rr=getr(i+1,j);
add(cd,rr,inf,0);
add(rr,cd,0,0);
}
if(j<n)
{
int rr=getr(i,j+1);
add(cd,rr,inf,0);
add(rr,cd,0,0);
}
}
add(S,1,2,0);
add(1,S,0,0);
add(getc(m,n),T,inf,0);
add(T,getc(m,n),0,0);
dinic();
printf("%d",cost);
return 0;
}
网络流最大费用流(传纸条)
猜你喜欢
转载自blog.csdn.net/richard__luan/article/details/81009863
今日推荐
周排行