Ombrophobic Bovines POJ

来源:互联网 发布:js实现上传文件的代码 编辑:程序博客网 时间:2024/06/11 04:27

传送门:POJ2391

题意:有n个牛场,每个牛场有初始牛群和一个避雨棚,每个牛场的避雨棚都有自己的最大容纳量,某些牛场之间有道路连接,牛走过这些道路需要花费一定量的时间,问最少多长时间能让所有的牛都找到一个避雨棚。

思路:这题和poj2112很相似,由于前两天刚做了poj2112,于是看完题就想到了二分+floyd+最大流,自信写完,然后样例也一遍过,还以为要1A了,然而却是无限的wa。。

正解:这题要加拆点操作,想知道为什么戳这里:http://blog.csdn.net/sdj222555/article/details/7771553

拆点是为了把整个图分为X部和Y部,因为这题的本质还是二分图多重匹配啊!

这题建图并不是很难,关键是要想到拆点。

代码:

//ISAP int#include <iostream>#include <cstdio>#include <cstring>#include <queue>#define ll long long#define MAXN 500#define INF 0x3f3f3f3f3f3f3f3f#define inf 0x3f3f3f3fusing namespace std;int n,N,M;//题目输入点数,边数struct Edge{int v,next;int cap,flow;}edge[MAXN*MAXN];int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];int have[MAXN],can[MAXN];int cnt=0,sum_of_cows; ll mp[MAXN][MAXN];void init(){cnt=0;memset(pre,-1,sizeof(pre)); }inline void add(int u,int v,int w,int rw=0)//加边 有向图三个参数,无向图四个 {edge[cnt].v=v;edge[cnt].cap=w;edge[cnt].flow=0;edge[cnt].next=pre[u];pre[u]=cnt++;edge[cnt].v=u;edge[cnt].cap=rw;edge[cnt].flow=0;edge[cnt].next=pre[v];pre[v]=cnt++;}bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长 {memset(dep,-1,sizeof(dep));memset(gap,0,sizeof(gap));gap[0]=1;dep[t]=0;queue<int>q;while(!q.empty())q.pop();q.push(t);//从汇点开始反向建层次图 while(!q.empty()){int u=q.front();q.pop();for(int i=pre[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量{dep[v]=dep[u]+1;gap[dep[v]]++;q.push(v);//if(v==s)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定 //break;}}}return dep[s]!=-1; }int isap(int s,int t){bfs(s,t);memcpy(cur,pre,sizeof(pre));int u=s;path[u]=-1;int ans=0;while(dep[s]<n)//迭代寻找增广路 {if(u==t){int f=inf;for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路 f=min(f,edge[i].cap-edge[i].flow);for(int i=path[u];i!=-1;i=path[edge[i^1].v]){edge[i].flow+=f;edge[i^1].flow-=f;}ans+=f;u=s;continue;}bool flag=false;int v;for(int i=cur[u];i!=-1;i=edge[i].next){v=edge[i].v;if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow){cur[u]=path[v]=i;//当前弧优化 flag=true;break;}}if(flag){u=v;continue;}int x=n;if(!(--gap[dep[u]]))return ans;//gap优化 for(int i=pre[u];i!=-1;i=edge[i].next){if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x){x=dep[edge[i].v];cur[u]=i;//常数优化 }}dep[u]=x+1;gap[dep[u]]++;if(u!=s)//当前点没有增广路则后退一个点 u=edge[path[u]^1].v; }  return ans;}int build(ll up){int source=0,sink=n=2*N+1;init();for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)if(mp[i][j]<=up)add(i,j+N,inf);for(int i=1;i<=N;i++)add(source,i,have[i]),add(i,i+N,inf);for(int i=1;i<=N;i++)add(i+N,sink,can[i]);return isap(source,sink);}void bi_search(ll L,ll R){ll l=L,r=R+1,mid;while(l<=r){mid=(l+r)>>1;if(build(mid)>=sum_of_cows)r=mid-1;elsel=mid+1;}if(r+1>R)cout<<-1;elsecout<<r+1;}void floyd(){ll l=INF,r=0;for(int k=1;k<=N;k++)for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)if(mp[i][j]>mp[i][k]+mp[k][j]){mp[i][j]=mp[i][k]+mp[k][j];l=min(mp[i][j],l);r=max(mp[i][j],r);}bi_search(l,r);}int main(){ll w;int u,v;sum_of_cows=0;scanf("%d%d",&N,&M);for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)mp[i][j]=INF;for(int i=1;i<=N;i++)scanf("%d%d",have+i,can+i),sum_of_cows+=have[i];for(int i=0;i<M;i++){scanf("%d%d%lld",&u,&v,&w);mp[u][v]=mp[v][u]=min(mp[u][v],w);}floyd();return 0;}
唉,还是太年轻啊。

0 0
原创粉丝点击