POJ2175.Evacuation Plan
【题意】
坐标系中,有n个建筑,给定坐标和建筑内人数和m个避难点,给定坐标和容量
定义每个人走的距离为|x1-x2|+|y1-y2|+1,问给定的方案是否是最优方案
【分析】
费用流消圈例题
我们按照给定方案建立残量网络,寻找负环进行增广即可
正常的消圈算法是不断找负环直到没有为止,但这道题目只要求找到一个更优的即可, 所以就直接找到一个环流1的流量即可
【代码】
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int maxn=105; const int maxm=1e5+5; struct dot { int x,y; }a[maxn],b[maxn]; int c[maxn],d[maxn],ans[maxn][maxn]; int head[maxm],n,m,T,dis[maxn][maxn]; int pre[maxm],cnt[maxm],vis[maxm]; int dist[maxm],viss[maxm]; int tot,sum[maxm]; struct edge { int to,nxt,v; }e[maxm<<1]; void add(int x,int y,int z) { e[++tot].to=y; e[tot].v=z; e[tot].nxt=head[x]; head[x]=tot; } int spfa(int s) { queue <int> q; q.push(s); memset(viss,0,sizeof(viss)); memset(dist,0x3f,sizeof(dist)); cnt[s]++ ; viss[s]=1; dist[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); viss[u]=0; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(dist[to]>dist[u]+e[i].v) { dist[to]=dist[u]+e[i].v; pre[to]=u; if(!viss[to]) { viss[to]=1; q.push(to); if(++cnt[to]>=T) return to; } } } } return -1; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); while(scanf("%d%d",&n,&m)!=EOF) { memset(head,0,sizeof(head)); memset(cnt,0,sizeof(cnt)); memset(vis,0,sizeof(vis)); memset(pre,0,sizeof(pre)); tot=1; T=m+n+1; for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&c[i]); for(int i=1;i<=m;i++) scanf("%d%d%d",&b[i].x,&b[i].y,&d[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dis[i][j]=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&ans[i][j]); if(ans[i][j]) add(j+n,i,-dis[i][j]); if(ans[i][j]!=c[i]) add(i,j+n,dis[i][j]); sum[j]+=ans[i][j]; } for(int i=1;i<=m;i++) { if(sum[i]>0) add(T,i+n,0); if(sum[i]<d[i]) add(i+n,T,0); } int id=spfa(T); if(id==-1) { printf("OPTIMAL\n"); continue; } printf("SUBOPTIMAL\n"); while(!vis[id]) { vis[id]=1; id=pre[id]; } int st=id; do { int u=pre[st]; int v=st; if(u<=n && v>n) ans[u][v-n]++; if(v<=n && u>n) ans[v][u-n]--; st=pre[st]; }while(st!=id); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d ",ans[i][j]); printf("\n"); } } return 0; }