您的位置:首页 > 运维架构

POJ-2391 Ombrophobic Bovines 二分+最大流+拆点

2012-12-05 18:54 309 查看
  题目链接:http://poj.org/problem?id=2391

  这个题目很容易想到二分求解,我开始没有拆点,wa了很多次!后来发现,如果不拆点,二分枚举答案是没有意义的。因为在网络中,已建立的边可以相互联通,那么它们的距离相加可能会超过二分的限制,导致没有意义。那么我们可以把每个区域拆成两个点,一个在X集合,一个在Y集合,增加一个源点s和汇点t。从s向每个X集合得点建立边,容量为这个区域本原有的奶牛数,从每个Y集合的点建立边,容量为这个区域奶牛数的限制。然后,如果X集合点和Y集合点之间的最短距离小于二分限制的话那就建立边,容量为X集合点的原有的奶牛数。那么最大流就是可容纳的奶牛数量了。这个题目还有些细节问题值得注意,就是ans=-1的情况,还有就是long long的注意。开始这个我没注意好,贡献了很多次wa!

//STATUS:G++_AC_188MS_1628KB
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
#define LL __int64
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAX=210,INF=0x3f3f3f3f;
const LL LLNF=0x3f3f3f3f3f3f3f3fLL;

struct Edge{
int u,v,cap;
}e[MAX*MAX*2];

LL w[MAX][MAX],d[MAX*2];
int first[MAX*2],next[MAX*MAX*2],p[MAX*2];
int wt[MAX][MAX],cur[MAX*2],num[MAX*2],nod[MAX][2],inq[MAX];
int n,m,s,t,mt,tar,hav;
LL maxlen,minlen;

void adde(int a,int b,int val)
{
e[mt].u=a;e[mt].v=b;
e[mt].cap=val;
next[mt]=first[a];first[a]=mt++;
e[mt].u=b;e[mt].v=a;
e[mt].cap=0;
next[mt]=first[b];first[b]=mt++;
}

void spfa(int s)
{
int i,x;
queue<int> q;
mem(inq,0);
mem(d,0x3f);
d[s]=0;
q.push(s);
while(!q.empty()){
x=q.front();q.pop();
inq[x]=0;
for(i=1;i<=n;i++){
if(wt[x][i]!=INF && d[x]+wt[x][i]<d[i]){
d[i]=d[x]+wt[x][i];
if(!inq[i]){
inq[i]=1;
q.push(i);
}
}
}
}
}

int augment()
{
int x=t,a=INF;
while(x!=s){
a=Min(a,e[p[x]].cap);
x=e[p[x]].u;
}
x=t;
while(x!=s){
e[p[x]].cap-=a;
e[p[x]^1].cap+=a;
x=e[p[x]].u;
}
return a;
}

int isap()
{
int i,flow=0,x,ok;
mem(d,0);mem(num,0);
num[0]=t+1;
for(i=0;i<=t;i++)cur[i]=first[i];
x=s;
while(d[s]<=t){
if(x==t){
flow+=augment();
x=s;
}
ok=0;
for(i=cur[x];i!=-1;i=next[i]){
if(e[i].cap && d[x]==d[e[i].v]+1){
ok=1;
p[e[i].v]=i;
cur[x]=i;
x=e[i].v;
break;
}
}
if(!ok){
int m=t;
for(i=first[x];i!=-1;i=next[i])
if(e[i].cap && d[e[i].v]<m)m=d[e[i].v];
if(--num[d[x]]==0)break;
num[d[x]=m+1]++;
cur[x]=first[x];
if(x!=s)x=e[p[x]].u;
}
}
return flow;
}

LL binary()
{
int i,j;
LL low=minlen-1,high=maxlen+1,mid;
while(low<high){
mid=(low+high)>>1;
mt=0;
mem(first,-1);
for(i=1;i<=n;i++){
if(nod[i][0]){
adde(s,i,nod[i][0]);
for(j=1;j<=n;j++)
if(w[i][j]<=mid)
adde(i,n+j,nod[i][0]);
}
adde(n+i,t,nod[i][1]);
}
int tt=isap();
if(tt<tar)low=mid+1;
else high=mid;
}
return low==maxlen+1?-1:low;
}

int main()
{
//   freopen("in.txt","r",stdin);
int i,j,a,b,val;
LL ans;
while(~scanf("%d%d",&n,&m))
{
tar=hav=0;
s=0;t=2*n+1;
maxlen=-LLNF,minlen=LLNF;
mem(w,0x3f);
mem(wt,0x3f);
for(i=1;i<=n;i++){
scanf("%d%d",&nod[i][0],&nod[i][1]);
tar+=nod[i][0];hav+=nod[i][1];
}
if(tar<=hav){
for(i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&val);
if(val<wt[a][b])wt[a][b]=wt[b][a]=val;
}
for(i=1;i<=n;i++){
spfa(i);
for(j=1;j<=n;j++){
w[j][i]=d[j];
if(d[j]<minlen && i!=j)minlen=d[j];
if(d[j]>maxlen && d[j]!=LLNF)maxlen=d[j];
}
}
ans=binary();
}
else {
ans=-1;
while(m--)scanf("%d%d%d",&a,&a,&a);
}

printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: