您的位置:首页 > 其它

洛谷P1401 城市

2018-03-12 22:52 281 查看

题目描述

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


二分答案+网络流。。。
一开始的思路是 spfa 记录最短路径,一条一条删边。
但是样例把 T 改为3 就炸了。。。
又看到 最长路最小——这TM不是二分答案么???

于是 二分答案+dinic。。。
把用过的边打上标记,没用过的边若流量小于二分的mid,设为0,否则设为1。
注:双向边。。。
附代码:#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 210
#define MAXM 40010
#define MAX 999999999
using namespace std;
int n,m,k,s,t,c=2;
int head[MAXN],deep[MAXN];
struct node{
int next,to,w;
bool vis;
}a[MAXM<<2],b[MAXM<<2];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void add(int u,int v,int w){
a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
a[c].to=u;a[c].w=0;a[c].next=head[v];head[v]=c++;
}
void reset(int x){
for(int i=2;i<c;i++){
if(a[i].w==0||a[i].w<=x||a[i].w==MAX)a[i].vis=true;
else a[i].vis=false;
b[i]=a[i];
if(a[i].w!=0&&a[i].w!=MAX)b[i].w=1;
}
}
bool bfs(){
int u,v;
queue<int> q;
for(int i=0;i<=n+2;i++)deep[i]=0;
deep[s]=1;
q.push(s);
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head[u];i;i=b[i].next){
v=b[i].to;
if(b[i].vis&&b[i].w&&!deep[v]){
deep[v]=deep[u]+1;
if(v==t)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int x,int limit){
if(x==t)return limit;
int v,cost=0,sum;
for(int i=head[x];i;i=b[i].next){
v=b[i].to;
if(b[i].vis&&b[i].w&&deep[v]==deep[x]+1){
sum=dfs(v,min(limit-cost,b[i].w));
if(sum>0){
b[i].w-=sum;
b[i^1].w+=sum;
cost+=sum;
if(cost==limit)break;
}
else deep[v]=-1;
}
}
return cost;
}
bool check(int x){
int ans=0;
reset(x);
while(bfs())ans+=dfs(s,MAX);
if(ans>=k)return true;
return false;
}
void init(){
int u,v,w,l,r=0,mid,ans=0;
n=read();m=read();k=read();
s=n+1;t=n+2;
for(int i=1;i<=m;i++){
u=read();v=read();w=read();
r=max(r,w);
add(u,v,w);add(v,u,w);
}
add(s,1,MAX);add(n,t,MAX);
while(l<=r){
mid=l+r>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
}
int main(){
init();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: