Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 3281 | Accepted: 1159 |
Description
Input
Output
Sample Input
4
3 2 0 0
0 0 3 3
6
1 2 4
1 3 10
1 4 12
2 3 6
2 4 8
3 4 5
0
Sample Output
6
Source
题目大意:
一共有n个城市,对应n个城市有两行输入,第一行表示每个城市拥有多少金子,第二行表示每个城市可以存放多少金子。接下来一个数m,表示边的数量,接下来m行三个元素,表示u,v之间有一条路权值为w,问如果想将所有金子都放到该存放的地方,需要经过的路径中,最长的那条边(权值最大的那条边)最小是多少。
思路:
1、经典最大流判定的问题,对应这条最长边最小可能是多少,很容易理解,我们可以从1枚举到最大边权值来判定,然而我们还知道从1枚举到最大边权值的过程中,一定是呈出这样的趋势:随着枚举的值越来越大,能够走得边就越来越多,能够运到位的金子就会越来越多,那么根据这个递增性,我们可以二分查找枚举这个值,从而来优化枚举的时间复杂度。
2、那么对应当前枚举出来的值mid,建图方式如下:
①建立一个源点,将源点连入各个有金子的点,权值设定为金子的数量。
②建立一个汇点,将所有能够存放金子的点连入汇点,权值为能够存放的金子的数量。
③将图中m条无向边权值小于等于mid的边全部加入网络中,权值设定为INF。
然后对应建好的图跑一遍最大流,得到的值就是当前情况最多能够运到位的金子的数量,如果maxlfow==sum(sum表示金子的总数量)那么当前mid值就是一个可行解,继续二分。
3、判定方法如上,一直二分下去,直到不能二分为止,维护可行解的最小值即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
struct node
{
int from;
int to;
int w;
int next;
}e[3000000];
int bian[200*200*5][4];
int a[20000];
int b[20000];
int divv[20000];
int cur[20000];
int head[20000];
int n,m,cont,ss,tt;
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void getmap(int mid)
{
ss=n+1;
tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
for(int i=0;i<n;i++)
{
if(a[i]>0)
{
add(ss,i+1,a[i]);
add(i+1,ss,0);
}
if(b[i]>0)
{
add(i+1,tt,b[i]);
add(tt,i+1,0);
}
}
for(int i=0;i<m;i++)
{
if(bian[i][2]<=mid)
{
add(bian[i][0],bian[i][1],0x3f3f3f3f);
add(bian[i][1],bian[i][0],0);
add(bian[i][1],bian[i][0],0x3f3f3f3f);
add(bian[i][0],bian[i][1],0);
}
}
}
int makedivv()
{
memset(divv,0,sizeof(divv));
divv[ss]=1;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
if(u==tt)return 1;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(divv[v]==0&&w)
{
divv[v]=divv[u]+1;s.push(v);
}
}
}
return 0;
}
int Dfs(int u,int maxflow,int tt)
{
if(u==tt)return maxflow;
int ret=0;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int w=e[i].w;
int v=e[i].to;
if(w&&divv[v]==divv[u]+1)
{
int f=Dfs(v,min(maxflow-ret,w),tt);
e[i].w-=f;
e[i^1].w+=f;
ret+=f;
if(ret==maxflow)return ret;
}
}
return ret;
}
int Slove(int mid)
{
getmap(mid);
int ans=0;
while(makedivv()==1)
{
memcpy(cur,head,sizeof(head));
ans+=Dfs(ss,0x3f3f3f3f,tt);
}
int sum=0;
for(int i=0;i<n;i++)
{
sum+=a[i];
}
if(sum==ans)return 1;
else return 0;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==0)break;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&b[i]);
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&bian[i][0],&bian[i][1],&bian[i][2]);
}
int ans=-1;
int mid;
int l=0;
int r=10000;
while(r>=l)
{
mid=(l+r)/2;
if(Slove(mid)==1)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
if(ans==-1)printf("No Solution\n");
else
printf("%d\n",ans);
}
}