caioj.cn1117 网络流入门3:路径中的最长边最小

1117: [视频]网络流入门3:路径中的最长边最小

时间限制: 2 Sec   内存限制: 128 MB
提交: 169   解决: 58
[ 提交][ 状态][ 讨论版]

题目描述

【题目描述】
千万要注意两个概念:边 和 路径(路径是由多条边组成,当然可以是一条边)
给出N(2 <= N <= 200)个点和P(1 <= P <= 40,000)条双向边,每条边的长度为(0~1 000 000),现在要求选出T(1 <= T <= 200)条“1至N”的路径, 任意两条路径上的边不能重复 ,并且要求这些路径中的 最长边 的长度最小。注意:两个点之间有可能多条边,出发点是1,终点是N。
【输入格式】
第一行三个整数: N, P, and T 。
下来P行,每行三个整数 x, y, L,描述一条边:从点x到y的双向边,长度为Li。
【输出格式】
求这T条路径中的的最长边的最小值。
Sample Input
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
Sample Output
5
提示:样例最后选择了两条路径 1 - 2 - 3 - 7 and 1 - 6 - 7.最长的路是5. 
数据很多,要用scanf读,用cin会超时

这是一道典型的网络流题目,很好理解,直接上代码:

#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
	int x,y,c,next,other;
}a[81000];int len,last[210],st,ed;
inline void ins(int x,int y,int c)
{
	len++;int k1=len;
	a[len].x=x;a[len].y=y;a[len].c=c;
	a[len].next=last[x];last[x]=len;
	
	len++;int k2=len;
	a[len].x=y;a[len].y=x;a[len].c=c;//因为是双向边,所以就不用为0 
	a[len].next=last[y];last[y]=len;
	
	a[k1].other=k2;
	a[k2].other=k1;
}
int head,tail,list[210],h[210];
inline bool bt_h()
{
	memset(h,0,sizeof(h));h[st]=1;
	list[1]=st;head=1;tail=2;
	while(head!=tail)
	{
		int x=list[head];
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(a[k].c>0 && h[y]==0)
			{
				h[y]=h[x]+1;
				list[tail++]=y;
			}
		}
		head++;
	}
	if(h[ed]>0) return true;
	return false;
}
int mymin(int x,int y){return x<y?x:y;}
int findflow(int x,int f)
{
	if(x==ed) return f;
	int s=0,t;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(a[k].c>0 && h[y]==h[x]+1 && s<f)
		{
			s+=(t=findflow(y,mymin(a[k].c,f-s)));
			a[k].c-=t;a[a[k].other].c+=t;
		}
	}
	if(s==0) h[x]=0;
	return s;
}
int x[41000],y[41000],d[41000];int N,M,T;
inline int check(int xx)//求所有长度不大于xx的路径的数量 
{
	len=0;memset(last,0,sizeof(last));
	for(int i=1;i<=M;i++)
		if(d[i]<=xx)//如果是不大于xx长度的边 
			ins(x[i],y[i],1);//因为是求方案数,所以流量为1,表示一种方案 
	int ans=0;
	while(bt_h()==true) ans=ans+findflow(st,2147483647); 
	return ans;
}
int main()
{
	scanf("%d%d%d",&N,&M,&T);
	st=1;ed=N;//起点和终点 
	int l=0,r=0;//二分查找的左右 
	for(int i=1;i<=M;i++)
	{
		scanf("%d%d%d",&x[i],&y[i],&d[i]);
		if(d[i]>r) r=d[i];//求最长的边 
	}
	int ans=0;
	while(l<=r)//二分查找 
	{
		int mid=(l+r)/2;
		if(check(mid)>=T)
		{
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsyzclb/article/details/80966722
cn
今日推荐