zoukankan      html  css  js  c++  java
  • 洛谷 P1401 城市(二分+网络流)

    题目描述

    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赋值。

    代码:

     1 #include<bits/stdc++.h>
     2 #define il inline
     3 #define debug printf("%d %s
    ",__LINE__,__FUNCTION__)
     4 using namespace std;
     5 il int gi()
     6 {
     7     int a=0;char x=getchar();bool f=0;
     8     while((x>'9'||x<'0')&&x!='-')x=getchar();
     9     if(x=='-')x=getchar(),f=1;
    10     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    11     return f?-a:a;
    12 }
    13 const int N=100005,inf=233333;
    14 int n,m,T,s,t=520,dis[400],h[500],cnt=1,ans;
    15 struct edge{
    16 int to,net,v;
    17 }e[N*2],p[N];
    18 il void add(int u,int v,int w)
    19 {
    20     e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt;
    21     e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt;
    22 }
    23 il bool bfs()
    24 {
    25     memset(dis,-1,sizeof(dis));
    26     queue<int> q;
    27     q.push(s),dis[s]=0;
    28     while(!q.empty())
    29     {
    30     //    debug;
    31         int u=q.front();q.pop();
    32         for(int i=h[u];i;i=e[i].net)
    33         if(dis[e[i].to]==-1&&e[i].v>0)
    34         dis[e[i].to]=dis[u]+1,q.push(e[i].to);
    35     }
    36     return dis[t]!=-1;
    37 }
    38 il int dfs(int u,int op)
    39 {
    40     if(u==t)return op;
    41     int flow=0,used=0;
    42     for(int i=h[u];i;i=e[i].net)
    43     {
    44         int v=e[i].to;
    45         if(dis[v]==dis[u]+1&&e[i].v>0)
    46         {
    47             used=dfs(v,min(op,e[i].v));
    48             if(!used)continue;
    49             flow+=used,op-=used;
    50             e[i].v-=used,e[i^1].v+=used;
    51             if(!op)break;
    52         }
    53     }
    54     if(!flow)dis[u]=-1;
    55     return flow;
    56 }
    57 il void add_edge(int x)
    58 {
    59     memset(h,0,sizeof(h));
    60     cnt=1;
    61     for(int i=1;i<=m;i++)
    62         if(p[i].v<=x)add(p[i].to,p[i].net,1),add(p[i].net,p[i].to,1);
    63 
    64 }
    65 il bool check(int x)
    66 {
    67     add_edge(x);
    68     int ans=0;
    69     while(bfs())ans+=dfs(s,inf);
    70     if(ans>=T)return 1;
    71     return 0;
    72 }
    73 int main()
    74 {
    75     n=gi(),m=gi(),T=gi();
    76     s=1,t=n;
    77     int l=1,r=0;
    78     for(int i=1;i<=m;i++)
    79         p[i].to=gi(),p[i].net=gi(),p[i].v=gi(),r=max(r,p[i].v);
    80 //    sort(p+1,p+m+1,cmp);
    81     while(l<=r)
    82     {
    83         int mid=(l+r)/2;
    84         if(check(mid))ans=mid,r=mid-1;
    85         else l=mid+1;
    86     }
    87     cout<<ans;
    88     return 0;
    89 }
  • 相关阅读:
    onSaveInstanceState和onRestoreInstanceState()
    Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性
    又优化了一下 Android ListView 异步加载图片
    ListView异步加载图片
    SpannableString 设置一段文字中部分字体颜色
    Android Studio apk 打包流程
    svn分支开发与主干合并(branch & merge)
    SVN使用教程之——分支、合并
    XMPP协议实现原理介绍
    监听器
  • 原文地址:https://www.cnblogs.com/five20/p/8213732.html
Copyright © 2011-2022 走看看