zoukankan      html  css  js  c++  java
  • POJ 2455

    原题地址:http://poj.org/problem?id=2455

    题目大意:给出一个N个点的无向图,中间有P条边,要求找出从1到n的T条通路,满足它们之间没有公共边,并使得这些通路中经过的最长的边的长度最短。两点之间允许有重边

    数据范围:2 <= N <= 200, 1 <= P <= 40,000,1 <= T <= 200,1 <= 每条路的长度L <= 1,000,000

    题目分析:

    看到“最大值最小”的第一反应就是二分最大长度k,满足T条通路没有公共边的第一反应就是将每条边的容量赋为1然后跑一遍最大流。这样算法就出来了:读入并建图,二分最大长度k,将所有长度小于等于 k 的边的容量设为1, 大于 k 的边容量设为0,然后以1为源点,n为汇点做一遍最大流,如果满足最大流大于等于T,则合要求继续二分,直至找出答案。

    一开始在双向边建图的时候有点犹豫。毕竟网络流要求每条边必须要有反向边。最开始的想法是将每条双向边都拆成两条单向边,对每条单向边都建立一条长度为无穷大的反向边(无穷大是为了保证二分时赋初始容量都将它们为0),但是后来证明这种想法是错误的:因为题目要求每条边只能走一次,但是按我的想法每条边可以正向走一次,反向走一次,加上题目中允许有重边,就使情况变得更加复杂。后来我发现网络流的反向边不一定要初始容量为0——就算我将这一条双向边的两个方向按照网络流的一对反向边来建立,初始容量都允许为1,无论正着流还是反着流这条边所能允许的总容量必然只有0或1……然后就想通了(希望能给这里想不太清楚的同学们一点帮助)

    然后这道题TLE到死……经过hockey指点才发现是我Dinic 写残了,应该到不能流的时候就退出但是我没有……改掉这一点之后,我加上当前弧优化的Dinic还是可以600+MS勉强AC的

    PS:网上有些人说重新建立源点和汇点,并连接一条从源点到1的容量为T的边,其实丝毫没有必要,直接以1为源点是可以的

      1 //date 20140118
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 const int maxn = 205;
      6 const int maxm = 80005;
      7 const int INF = 0x7FFFFFFF;
      8 
      9 inline int getint()
     10 {
     11     int ans(0); char w = getchar();
     12     while('0' > w || w > '9')w = getchar();
     13     while('0' <= w && w <= '9')
     14     {
     15         ans = ans * 10 + w - '0';
     16         w = getchar();
     17     }
     18     return ans;
     19 }
     20 
     21 inline int min(int a, int b){return a < b ? a : b;}
     22 inline int max(int a, int b){return a > b ? a : b;}
     23 
     24 int n, m, T;
     25 int s, t;
     26 struct edge
     27 {
     28     int v, w, c, next;
     29 }E[maxm];
     30 int a[maxn];
     31 int now[maxn];
     32 int nedge;
     33 int lab[maxn];
     34 
     35 inline void add(int u, int v, int w, int c)
     36 {
     37     E[++nedge].v = v;
     38     E[nedge].c = c;
     39     E[nedge].w = w;
     40     E[nedge].next =  a[u];
     41     a[u] = nedge;
     42 }
     43 
     44 int maxl, minl;
     45 
     46 inline int label()
     47 {
     48     static int q[maxn];
     49     int l = 0, r = 1;
     50     memset(lab, 0xFF, sizeof lab);
     51     q[1] = s; lab[s] = 0;
     52     while(l < r)
     53     {
     54         int x = q[++l];
     55         for(int i = a[x]; i; i = E[i].next)
     56             if(E[i].c == 1 && lab[E[i].v] == -1)
     57             {
     58                 lab[E[i].v] = lab[x] + 1;
     59                 q[++r] = E[i].v;
     60             }
     61     }
     62     return lab[t] != -1;
     63 }
     64 
     65 int Dinic(int v, int f)
     66 {
     67     if(v == t)return f;
     68     int res = 0, w;
     69     for(int i = now[v]; i; i = now[v] = E[i].next)
     70         if((E[i].c == 1) && (f > 0) && (lab[v] + 1 == lab[E[i].v]) && (w = Dinic(E[i].v, min(f, E[i].c))))
     71         {
     72             E[i].c -= w;
     73             E[i ^ 1].c += w;
     74             f -= w;
     75             res += w;
     76             if(f == 0)break;
     77         }
     78     if(res == 0)lab[v] = -1;
     79     return res;
     80 }
     81 
     82 inline int max_flow()
     83 {
     84     int ans = 0;
     85     while(label())
     86     {
     87         for(int i = s; i <= t; ++i)now[i] = a[i];
     88         ans += Dinic(s, INF);
     89     }
     90     return ans;
     91 }
     92 
     93 inline bool check(int k)
     94 {
     95     for(int i = 2; i <= nedge; i += 2)
     96         if(E[i].w <= k)E[i].c = E[i ^ 1].c = 1; else E[i].c = E[i ^ 1].c = 0;
     97     int ans = max_flow();
     98     //printf("%d
    ", ans);
     99     return ans >= T;
    100 }
    101 
    102 inline int solve(int l, int r)
    103 {
    104     int mid;
    105     while(l < r)
    106     {
    107         mid = (l + r) >> 1;
    108         if(check(mid))r = mid;
    109         else l = mid + 1;
    110     }
    111     return l;
    112 }
    113 
    114 int main()
    115 {
    116     n = getint(); m = getint(); T = getint();
    117     nedge = 1; maxl = 0; minl = INF;
    118     s = 1; t = n;
    119     int x, y, z;
    120     for(int i = 1; i <= m; ++i)
    121     {
    122         x = getint(); y = getint(); z = getint();
    123         add(x, y, z, 0);
    124         add(y, x, z, 0);
    125         maxl = max(maxl, z);
    126         minl = min(minl, z);
    127     }
    128     int ans = solve(minl, maxl);
    129     printf("%d
    ", ans);
    130     return 0;
    131 }

    小结:建图还是需要多加思考多加练习,代码模板也是需要不断完善的,加油~

  • 相关阅读:
    电视剧的拍摄和发行
    常用键盘快捷键
    河北省各城市名称由来
    爱情16谈
    人生赏心十六件乐事
    Android——apk反编译
    Android.mk
    Android——init可执行程序
    Android启动脚本init.rc(2)
    MountService初探
  • 原文地址:https://www.cnblogs.com/w007878/p/3525593.html
Copyright © 2011-2022 走看看