#负环,费用流#ZOJ 1553 Evacuation Plan
题目
一个城市有 \(n\) 座建筑物,每个建筑物里面有一些人,为了在战争爆发时这些人都可以避难,城市里面建了 \(m\) 座避难所。每座避难所只能容纳有限人数。
给出每个建筑物的坐标 \((x_i,y_i)\) 和避难所的坐标 \((p_j,y_j)\)。一个人从第 \(i\) 个建筑物逃离到第 \(j\) 个避难所花费的时间是 \(|x_i-p_j|+|y_i-q_j|+1\)。
现在给你一种避难方案,问你这种方案是否是时间总数最小的?如果不是,请输出一种比当前更优的方案(不一定最优)。
分析
这个费用流的模型很容易建出来,并将当前流量赋以给出的避难方案的流量,如果比当前更优,说明原图存在负环可使流量不变而费用减少,
那么对残量网络找负环,找到负环那么用负环更新答案,否则就是不存在更优解。
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
using namespace std;
const int N=216,inf=0x3f3f3f3f; queue<int>q; struct node{int y,w,f,next;}e[N*N];
int as[N],dis[N],v[N],_T,dep[N],cnt[N],x[N],y[N],C[N],X[N],Y[N],a[N],A[N],b[N][N],c[N],pre[N],n,m,S,T,et=1,ans,ANS,Test;
void add(int x,int y,int w,int W,int f){
e[++et]=(node){y,w-W,f,as[x]},as[x]=et;
e[++et]=(node){x,W,-f,as[y]},as[y]=et;
}
int Abs(int x){return x<0?-x:x;}
int spfa(){
for (int i=1;i<=_T;++i) dis[i]=inf,v[i]=cnt[i]=dep[i]=0;
while (!q.empty()) q.pop();
dis[_T]=0,v[_T]=1,q.push(_T);
while (!q.empty()){
int x=q.front(); q.pop();
if (++cnt[x]==_T) return x;
for (int i=as[x];i;i=e[i].next)
if (e[i].w&&dis[e[i].y]>dis[x]+e[i].f){
dis[e[i].y]=dis[x]+e[i].f,dep[e[i].y]=dep[x]+1,pre[e[i].y]=x;
if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
}
v[x]=0;
}
return 0;
}
int main(){
while (scanf("%d%d",&n,&m)==2){
S=n+m+1,T=S+1,_T=T+1,et=1;
for (int i=1;i<=n;++i) scanf("%d%d%d",&x[i],&y[i],&a[i]);
for (int i=1;i<=m;++i) scanf("%d%d%d",&X[i],&Y[i],&A[i]);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j){
scanf("%d",&b[i][j]);
add(i,j+n,inf,b[i][j],Abs(x[i]-X[j])+Abs(y[i]-Y[j])+1);
c[i]+=b[i][j],C[j]+=b[i][j];
}
for (int i=1;i<=n;++i) add(S,i,a[i],c[i],0);
for (int i=1;i<=m;++i) add(i+n,T,A[i],C[i],0);
for (int i=1;i<=T;++i) add(_T,i,1,0,0);
if (!(ans=spfa())) printf("OPTIMAL\n");
else{
printf("SUBOPTIMAL\n");
for (int i=1;i<=_T;++i) v[i]=0;
while (!v[ans]) v[ans]=1,ans=pre[ans];
int t=ans;
do{
if (t<=n&&pre[t]<S) ++b[t][pre[t]-n];
if (pre[t]<=n&&t<S) --b[pre[t]][t-n];
t=pre[t];
}while (t!=ans);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) printf("%d%c",b[i][j],j==m?10:32);
}
for (int i=1;i<=_T;++i) c[i]=v[i]=C[i]=pre[i]=as[i]=0;
}
return 0;
}

浙公网安备 33010602011771号