View Code
//题目类型:最大流+二分搜索 
//本题的关键在于理解题意:本题不是求最短路,而是要求路上的最长的一部分最小,故可以用二分法解决,至于路的条数,则可以求图的最大流 
#include <iostream>
#include <queue>
//#include <conio.h>
using namespace std;
#define parray 40001
#define narray 201
const int INF = 10000000;
typedef struct edge
{
    int u;
    int v;
    int w;
}edge;
edge edges[parray];
int n,p,t;
int r[narray][narray];
 
int d[narray];           //标号
int num[narray];         //num[i]表示标号为i的顶点数有多少
int pre[narray];         //记录前驱 
void ini_d(int s,int t) //BFS计算标号,汇点t标号为0
{
    int k;
    queue<int>Q;
 
    memset(d,1,sizeof(d));          //将距离设置成为无穷大,此处亦可以使用for循环实现 
    memset(num,0,sizeof(num));
 
    Q.push(t);
    d[t]=0;                   //汇点的标号为0 
    num[0]=1;
    while (!Q.empty())
    {
        k=Q.front(),Q.pop();
        for (int i=1;i<=n;i++)       //遍历所有的结点 
        {
            if (d[i]>=n&&r[i][k]>0) //此处要特别注意,通过frontint的值改变其他的距离标号
            {
                d[i]=d[k]+1;
                Q.push(i);
                num[d[i]]++;
            }
        }
    }
} 
int findAlowArc(int i)       //从i出发寻找允许弧
{
    int j;
    for (j=1;j<=n;j++) if (r[i][j]>0&&d[i]==d[j]+1) return j;
 
    return -1;
} 
int reLable(int i)         //重新标号
{
    int mm=INF;
    for (int j=1;j<=n;j++)
        if (r[i][j]>0) mm=min(mm,d[j]+1);
 
    return mm==INF?n:mm;
}
 
int maxFlow(int s,int t)      //从源点s出发的最大流
{
    int flow=0,i=s,j;
    int delta;              //增量
 
    memset(pre,-1,sizeof(pre));
    while (d[s]<n)
    {
        j=findAlowArc(i);
        if (j>=1)
        {
            pre[j]=i;                     
            i=j;                //从前往后找 
            if (i==t)           //更新残留网络
            {
                delta=INF;
                for (i=t;i!=s;i=pre[i]) delta=min(delta,r[pre[i]][i]); //找到增广路径的增量 
                for (i=t;i!=s;i=pre[i]) r[pre[i]][i] -= delta, r[i][pre[i]] += delta; //更改流量 
                flow += delta;
            }
        }
        else
        {
            int x=reLable(i);       //重新标号
            num[x]++;
            num[d[i]]--;
            if (num[d[i]]==0) return flow;      //间隙优化
            d[i]=x;
            if (i!=s) i=pre[i];
        }
    } 
    return flow;
}
 
void build(int length)
{
     int i,j;
     memset(r,0,sizeof(r));
     for(i=1;i<=p;++i)
     {
         if(edges[i].w<=length)
         {
             r[edges[i].u][edges[i].v]++;
             r[edges[i].v][edges[i].u]++;
         }
     }
}
int main()
{
    //freopen("1.txt","r",stdin);
    int i,j;
    int src,des;
    while(scanf("%d%d%d",&n,&p,&t)!=-1)
    {
         for(i=1;i<=p;++i)
         {
             scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w);
         }
         src = 1;
         des = n;
         int l = 0,h = 1000000,mid;
         while(l<h)
         {
             mid = (l+h)/2;
             build(mid);
             ini_d(src,des);
             if(maxFlow(src,des)>=t) h=mid;
             else l = mid+1;
         }
         printf("%d\n",h);
    }
    //getch();
    return 0;
}

别人的标号法最大流模板,收藏学习了。