[费用流 消圈原理] POJ 2175 Evacuation Plan

这个建图不难想吧 然后就是找到一个负环 增广一通就好了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline bool read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; return 1;
}

const int N=205;

struct edge{
  int u,v,w,next;
}G[N*N];
int head[N],inum=1;
inline void add(int u,int v,int w,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

int vst[N];
int ins[N],dis[N],pre[N];
int cnt[N];
int l,r,Q[100005];
int S,T;

#define V G[p].v

inline int SPFA(int s){
  l=r=-1;
  for (int i=1;i<=T;i++) dis[i]=1<<30,pre[i]=0,ins[i]=0,cnt[i]=0;
  Q[++r]=s; ins[s]=1; dis[s]=0; cnt[s]++;
  while (l<r){
    int u=Q[++l]; ins[u]=0;
    for (int p=head[u];p;p=G[p].next)
      if (dis[V]>dis[u]+G[p].w){
	dis[V]=dis[u]+G[p].w; pre[V]=u;
	if (!ins[V]){
	  Q[++r]=V; ins[V]=1; 
	  if ((++cnt[V])>T)
	    return V;
	}
      }
  }
  return -1;
}

int n,m;
int tot[N],Map[N][N];
int xs[N],ys[N],ws[N];

inline int Dis(int i,int j){
  return abs(xs[i]-xs[j])+abs(ys[i]-ys[j]);
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  while (read(n) && read(m)){
    S=n+m+2; T=n+m+1;
    for (int i=1;i<=n+m;i++)
      read(xs[i]),read(ys[i]),read(ws[i]);
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++){
	read(Map[i][j]);
	tot[j]+=Map[i][j];
	add(i,n+j,Dis(i,n+j),++inum);
	if (Map[i][j]) add(n+j,i,-Dis(i,n+j),++inum);
      }
    for (int j=1;j<=m;j++)
      if (tot[j]){
	add(T,n+j,0,++inum);
	if (tot[j]<ws[n+j]) add(n+j,T,0,++inum);
      }
    int u=-1;
    for (int i=1;i<=T && u==-1;i++)
      u=SPFA(i);
    if (u==-1)
      printf("OPTIMAL\n");
    else{
      printf("SUBOPTIMAL\n");
      cl(vst);
      int v=u,now;  
      while(vst[pre[v]]==0){  
        vst[v]=1;  
        v=pre[v];  
      }  
      now=v;  
      do{
	if(pre[now]<=n && now>n) Map[pre[now]][now-n]++;   
	if(pre[now]>n && now<=n) Map[now][pre[now]-n]--; 
	now=pre[now];  
      }while(now!=v);  
      for(int i=1;i<=n;i++,printf("\n"))  
	for(int j=1;j<=m;j++)
	  printf("%d ",Map[i][j]);  
    }
    cl(tot); cl(head); inum=1; cl(vst);
  }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值