poj 2455 网络流
这道题目算是让我学到了不少建图的细节
题目保证从s到t有T条无相同道路的路径,即每条边只能用一次,每个点可以多次经过
然后要求所有的路径中最大的边的最小值
每条边只能用一次,可以联想到网络流,边容量为1
求最小的最大可以用二分
判断二分的值是否满足条件:s、t的最大流是否>=T
讲一下建图的细节
双向建图,即满足条件的每条边的容量都为1,可以双向流
而对于zoj 3583,每个点只能经过一次(每条边当然也只能经过一次),而且是无向图,所以也需要双向流,但是由于一个点只能经过一次,就需要拆点了,拆点后再求最大流就能保证最大的流只经过每个点最多一次。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<string.h>
const int MAX=1010;
const int INF=1000000000;
struct
{
int v,c,next;
}edge[1000000];
int E,head[MAX];
int gap[MAX],cur[MAX];
int pre[MAX],dis[MAX];
void add_edge(int s,int t,int c)
{
edge[E].v=t; edge[E].c=c;
edge[E].next=head[s];
head[s]=E++;
edge[E].v=s; edge[E].c=c;
edge[E].next=head[t];
head[t]=E++;
}
int min(int a,int b){return (a==-1||b<a)?b:a;}
int SAP(int s,int t,int n)
{
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
int i;
for(i=0;i<n;i++)cur[i]=head[i];
int u=pre[s]=s,maxflow=0,aug=-1,v;
gap[0]=n;
while(dis[s]<n)
{
loop: for(i=cur[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[u]==dis[v]+1)
{
aug=min(aug,edge[i].c);
pre[v]=u;
cur[u]=i;
u=v;
if(u==t)
{
for(u=pre[u];v!=s;v=u,u=pre[u])
{
edge[cur[u]].c-=aug;
edge[cur[u]^1].c+=aug;
}
maxflow+=aug;
aug=-1;
}
goto loop;
}
}
int mindis=n;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[v]<mindis)
{
cur[u]=i;
mindis=dis[v];
}
}
if((--gap[dis[u]])==0)break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return maxflow;
}
int n,m,T;
struct node{
int a,b,c;
}p[40010];
int g[MAX][MAX];
void build(int mid)
{
memset(head,-1,sizeof(head));
E=0;
for(int i=0;i<m;i++)
{
if(p[i].c<=mid)
add_edge(p[i].a,p[i].b,1);
}
}
int main()
{
int a,b,w;
while(scanf("%d%d%d",&n,&m,&T)!=EOF)
{
memset(g,0,sizeof(g));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
}
int l=0,r=1000000,mid;
int best=-1;
while(l<=r)
{
mid=(l+r)>>1;
build(mid);
if(SAP(1,n,n)>=T)
{
best=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",best);
}
return 0;
}