POJ 2391 floyd+二分+最大流

题意:

有N块田,每块田下雨时可以容纳a[i]头牛,每块田现在有b[i]头牛,给出一些田与田之间的无向路径及距离,问下雨时最少多少时间后所有牛都能到避雨的地方。

题解:

明显又是二分答案。floyd求取两点间最短路

PS:要用long long!!!

一开始我想的是三层的图:

①n个点表示n块田    ②和③各n个点(灭个点i和i',拆点限制容量)

S连①中的点容量a[i],表示一开始有a[i]头奶牛在i点

①中的点连②中的i,当且仅当两块田之间的距离小于二分值时

②和③对应点相连,限制流量

③中的点和T连INF的边

这样果断tle了。

后来发现③中的点没有用,直接在②和T之间限流即可,优化后就ac了~

View Code
  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 
  7 #define N 1000
  8 #define M 140000
  9 #define INF 1LL<<55
 10 
 11 using namespace std;
 12 
 13 int head[N],to[M],next[M];
 14 __int64 map[N][N],len[M],l,r,mid,sum,num[N],hold[N];
 15 int q[M*10],layer[N];
 16 int n,m,S,T,cnt,tot;
 17 
 18 struct PX
 19 {
 20     __int64 a,b,c;
 21 }px[M];
 22 
 23 inline bool cmp(const PX &a,const PX &b)
 24 {
 25     return a.c<b.c;
 26 }
 27 
 28 inline void floyd()
 29 {
 30     for(int k=1;k<=n;k++)
 31         for(int i=1;i<=n;i++)
 32             for(int j=1;j<=n;j++)
 33                 map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
 34     for(int i=1;i<=n;i++)
 35         for(int j=1;j<=n;j++)
 36             r=max(r,map[i][j]);
 37 }
 38 
 39 inline void add(int u,int v,__int64 w)
 40 {
 41     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
 42     to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
 43 }
 44 
 45 inline void read()
 46 {
 47     memset(head,-1,sizeof head); cnt=0;
 48     for(int i=1;i<=n;i++)
 49     {
 50         for(int j=1;j<=n;j++)
 51             map[i][j]=INF;
 52         map[i][i]=0;
 53     }
 54     r=0; S=0; T=n+n+1;
 55     for(int i=1;i<=n;i++)
 56     {
 57         scanf("%I64d%I64d",&num[i],&hold[i]);
 58         sum+=num[i];
 59     }
 60     __int64 c;
 61     for(int i=1,a,b;i<=m;i++)
 62     {
 63         scanf("%d%d%I64d",&a,&b,&c);
 64         map[a][b]=map[b][a]=min(c,map[a][b]);
 65     }
 66     floyd();
 67     tot=0;
 68     for(int i=1;i<=n;i++)
 69         for(int j=1;j<=n;j++)
 70             px[++tot].a=i,px[tot].b=j,px[tot].c=map[i][j];
 71     sort(px+1,px+1+tot,cmp);
 72 }
 73 
 74 inline void build()
 75 {
 76     memset(head,-1,sizeof head); cnt=0;
 77     for(int i=1;i<=tot;i++)
 78     {
 79         if(px[i].c>mid) break;
 80         add(px[i].a,px[i].b+n,INF);
 81     }
 82     for(int i=1;i<=n;i++)
 83     {
 84         add(i+n,T,hold[i]);
 85         add(S,i,num[i]);
 86     }
 87 }
 88 
 89 inline bool bfs()
 90 {
 91     memset(layer,-1,sizeof layer);
 92     int h=1,t=2,sta;
 93     q[1]=S; layer[S]=0;
 94     while(h<t)
 95     {
 96         sta=q[h++];
 97         for(int i=head[sta];~i;i=next[i])
 98             if(len[i]&&layer[to[i]]<0)
 99             {
100                 layer[to[i]]=layer[sta]+1;
101                 q[t++]=to[i];
102             }
103     }
104     return layer[T]!=-1;
105 }
106 
107 inline __int64 find(int u,__int64 cur_flow)
108 {
109     if(u==T) return cur_flow;
110     __int64 res=0,tmp;
111     for(int i=head[u];~i&&res<cur_flow;i=next[i])
112         if(len[i]&&layer[to[i]]==layer[u]+1)
113         {
114             tmp=find(to[i],min(cur_flow-res,len[i]));
115             len[i]-=tmp; len[i^1]+=tmp; res+=tmp;
116         }
117     if(!res) layer[u]=-1;
118     return res;
119 }
120 
121 __int64 dinic()
122 {
123     __int64 ans=0;
124     while(bfs()) ans+=find(S,INF);
125     return ans;
126 }
127 
128 inline void go()
129 {
130     l=0; 
131     __int64 ans=-1;
132     r+=1000;
133     while(l<=r)
134     {
135         mid=(l+r)>>1;
136         build();
137         if(dinic()==sum) ans=mid,r=mid-1;
138         else l=mid+1;
139     }
140     if(ans>=INF) puts("-1");
141     else printf("%I64d\n",ans);
142 }
143 
144 int main()
145 {
146     while(scanf("%d%d",&n,&m)!=EOF) read(),go();
147     return 0;
148 }
没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2850379.html