洛谷 P1401 城市(二分+网络流)
2018-01-06 11:33
309 查看
题目描述
N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能重复用。输入输出格式
输入格式:第1行三个整数N,M,T用空格隔开。
第2行到P+1行,每行包括三个整数Ai,Bi,Li表示城市Ai到城市Bi之间有一条长度为Li的道路。
输出格式:
输出只有一行,包含一个整数,即经过的这些道路中最长的路的最小长度。
输入输出样例
输入样例#1:7 9 2 1 2 2 2 3 5 3 7 5 1 4 1 4 3 1 4 5 7 5 7 1 1 6 3 6 7 3
输出样例#1:
5
Solution:
题目求的是最大边的最小值,可以下意识地想到二分答案,但是有限制条件(即从1到n的路径要大于等于t条)这时我们思考应该如何去check。可以很容易想到网络流吧(反正我是这样想的),因为题目中说了一条边只能用一次(这不就限制了容量嘛),而且可以把S当作1、T当作n,这样不就是求最大流啊,只要总流量大于t我们就将上界缩小,否则将下界增大,直到最后无法再check为止,输出ans就ok了。
建图时,我们可以先保存边集数组,二分边界L赋值为1、R赋值为边的最大值,然后每次二分出mid值,若边长小于等于mid则加一条容量为1的边,check时就直接跑最大流就好了,最后输出ans题目解决。。
注意:每次check记得清head数组并给cnt赋值。
代码:
#include<bits/stdc++.h> #define il inline #define debug printf("%d %s\n",__LINE__,__FUNCTION__) using namespace std; il int gi() { int a=0;char x=getchar();bool f=0; while((x>'9'||x<'0')&&x!='-')x=getchar(); if(x=='-')x=getchar(),f=1; while(x>='0'&&x<='9')a=a*10+x-48,x=getchar(); return f?-a:a; } const int N=100005,inf=233333; int n,m,T,s,t=520,dis[400],h[500],cnt=1,ans; struct edge{ int to,net,v; }e[N*2],p ; il void add(int u,int v,int w) { e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt; e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt; } il bool bfs() { memset(dis,-1,sizeof(dis)); queue<int> q; q.push(s),dis[s]=0; while(!q.empty()) { // debug; int u=q.front();q.pop(); for(int i=h[u];i;i=e[i].net) if(dis[e[i].to]==-1&&e[i].v>0) dis[e[i].to]=dis[u]+1,q.push(e[i].to); } return dis[t]!=-1; } il int dfs(int u,int op) { if(u==t)return op; int flow=0,used=0; for(int i=h[u];i;i=e[i].net) { int v=e[i].to; if(dis[v]==dis[u]+1&&e[i].v>0) { used=dfs(v,min(op,e[i].v)); if(!used)continue; flow+=used,op-=used; e[i].v-=used,e[i^1].v+=used; if(!op)break; } } if(!flow)dis[u]=-1; return flow; } il void add_edge(int x) { memset(h,0,sizeof(h)); cnt=1; for(int i=1;i<=m;i++) if(p[i].v<=x)add(p[i].to,p[i].net,1),add(p[i].net,p[i].to,1); } il bool check(int x) { add_edge(x); int ans=0; while(bfs())ans+=dfs(s,inf); if(ans>=T)return 1; return 0; } int main() { n=gi(),m=gi(),T=gi(); s=1,t=n; int l=1,r=0; for(int i=1;i<=m;i++) p[i].to=gi(),p[i].net=gi(),p[i].v=gi(),r=max(r,p[i].v); // sort(p+1,p+m+1,cmp); while(l<=r) { int mid=(l+r)/2; if(check(mid))ans=mid,r=mid-1; else l=mid+1; } cout<<ans; return 0; }
相关文章推荐
- AC日记——城市 洛谷 P1401
- 洛谷P1401 城市
- P1401 城市(30分,正解网络流)
- [洛谷 P2857][caioj 1120] 牛选牛圈 --- 二分+网络流-最大流
- 【bzoj1822】[JSOI2010]Frozen Nova 冷冻波 计算几何+二分+网络流最大流
- 【bzoj3130】[Sdoi2013]费用流 二分+网络流最大流
- 2095: [Poi2010]Bridges 二分+混合图欧拉回路(网络流)
- POJ 2112 二分+网络流
- BZOJ 4443(SCOI2015)网络流+二分答案 解题报告
- SPOJ 287 网络流最大流+二分答案 解题报告
- poj2391(floyd+二分+网络流判定)
- 洛谷2763:[网络流24题]试题库问题——题解
- 网络流入门 洛谷P1231
- 【BZOJ5251】【八省联考2018】劈配(网络流,二分答案)
- POJ 2455 Secret Milking Machine(搜索-二分,网络流-最大流)
- BZOJ 1189([HNOI2007]紧急疏散evacuate-网络流二分+拆点)
- 洛谷 3938 [NOIP模拟] 斐波那契 二分+找规律
- 【BZOJ 2756】[SCOI2012]奇怪的游戏 网络流+二分
- SPOJ NETADMIN - Smart Network Administrator(二分)(网络流)
- hdu 3081 二分 + 并查集 + 网络流