• [BZOJ1001](BeiJingOI 2006)狼抓兔子


    Description   Source: Beijing2006 [BJOI2006]

    八中OJ上本题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:


    左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

    Input

    第一行为N,M.表示网格的大小,N,M均小于等于1000.接下来分三部分 第一部分共N行,每行M-1个数,表示横向道路的权值. 第二部分共N-1行,每行M个数,表示纵向道路的权值. 第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 输入文件保证不超过10M

    Output

    输出一个整数,表示参与伏击的狼的最小数量.

    Sample Input

    3 4
    5 6 4
    4 3 1
    7 5 3
    5 6 7 8
    8 7 6 5
    5 5 5
    6 6 6

    Sample Output

    14

    【分析】

         乍一看题,心想,bzoj似乎也不过如此啊,这不是最小割裸题吗?不要急,我们来看看数据范围……N,M均小于等于1000,而节点总数为MN……请告诉我比$O(VE)$ 更优的网络流怎么写= =

        很快我们就可以发现,根据这道题目的特殊性,我们得到的是一张平面图。图论告诉我们,每张平面图都有与之相对应的对偶图,而原图的“割”与它的对偶图的”路径“一一对应(详见周冬的论文《两极相同——浅析最大最小定理在信息学竞赛中的应用》)。于是我们可以把网格中的点和面互换,再把从S到T的连线上下两侧分别拆成两个点,求这两个点之间的最短路即可。

        (我的代码没有利用图的“边数有限”这一特点,还是用一个vector储存了邻接表,在有些OJ上可能会超时。

      1 /**************************************************************
      2     Problem: 1001
      3     User: 935671154
      4     Language: C++
      5     Result: Accepted
      6     Time:8536 ms
      7     Memory:104700 kb
      8 ****************************************************************/
      9  
     10 #include <iostream>
     11 #include <cctype>
     12 #include <cstdio>
     13 #include <vector>
     14 #include <algorithm>
     15 #include <cmath>
     16 #include <queue>
     17 using namespace std;
     18 inline void getd(int &x){
     19     char c = getchar();
     20     bool minus = 0;
     21     while(!isdigit(c) && c != '-')c = getchar();
     22     if(c == '-')minus = 1, c = getchar();
     23     x = c - '0';
     24     while(isdigit(c = getchar()))x = x * 10 + c - '0';
     25     if(minus)x = -x;
     26 }
     27 /*======================================================*/
     28 const int maxn = 2000003, INF = 0x3f3f3f3f;
     29 #define pb push_back
     30 struct edge{
     31     int to, w;
     32     edge(int t, int W):to(t), w(W){}
     33 };
     34 vector<edge> adj[maxn];
     35 int N, M, To, dis[maxn] = {0};
     36  
     37 inline bool init(){
     38     int i, j, k, t, d;
     39     getd(N), getd(M);
     40     if(N == 1){
     41         int ans = INF;
     42         for(i = 1;i < M;++i)
     43             getd(t), ans = min(ans, t);
     44         printf("%d ", ans);
     45         return 0;
     46     }
     47     if(M == 1){
     48         int ans = INF;
     49         for(i = 1;i < N;++i)
     50             getd(t), ans = min(ans, t);
     51         printf("%d ", ans);
     52         return 0;
     53     }
     54     To = ((N-1) * (M-1) * 2) + 1;
     55     //横向道路
     56     d = 2 * M - 3;
     57     for(i = k = 1;i < M;++i, k+=2){
     58         getd(t);
     59         adj[0].pb(edge(k, t));
     60     }
     61     for(i = 2;i < N;++i){
     62         for(j = 1;j < M;++j, k+=2){
     63             getd(t);
     64             adj[k].pb(edge(k-d, t));
     65             adj[k-d].pb(edge(k, t));
     66         }
     67     }
     68     for(j = 1, k = To-2*(M-2)-1;j < M;++j, k+=2){
     69         getd(t);
     70         adj[k].pb(edge(To, t));
     71     }
     72     //纵向道路
     73     for(i = 1,k = 2;i < N;++i){
     74         getd(t);
     75         adj[k].pb(edge(To, t));
     76         for(j = 2,k+=2;j < M;++j,k+=2){
     77             getd(t);
     78             adj[k].pb(edge(k-3, t));
     79             adj[k-3].pb(edge(k, t));
     80         }
     81         getd(t);
     82         adj[0].pb(edge(k-3, t));
     83     }
     84     //斜向道路
     85     for(i = 1, k = 1;i < N;++i){
     86         for(j = 1;j < M;++j, k += 2){
     87             getd(t);
     88             adj[k].pb(edge(k+1, t));
     89             adj[k+1].pb(edge(k, t));
     90         }
     91     }
     92     for(i = 1;i <= To;++i)
     93         dis[i] = INF;
     94     return 1;
     95 }
     96 queue<int> Q;
     97 bool inQ[maxn] = {1};
     98 inline void work(){
     99     Q.push(0);
    100     int t;
    101     vector<edge>::iterator it;
    102     while(!Q.empty()){
    103         t = Q.front();Q.pop();inQ[t] = 0;
    104         for(it = adj[t].begin();it != adj[t].end();++it)
    105             if(dis[t] + it->w < dis[it->to]){
    106                 dis[it->to] = dis[t] + it->w;
    107                 if(!inQ[it->to])
    108                     Q.push(it->to), inQ[it->to] = 1;
    109             }
    110     }
    111     printf("%d ", dis[To]);
    112 }
    113  
    114 int main(){
    115     #if defined DEBUG
    116     freopen("test""r", stdin);
    117     #endif
    118      
    119     if(init())
    120         work();
    121      
    122     #if defined DEBUG
    123     cout << endl << (double)clock()/CLOCKS_PER_SEC << endl;
    124     #endif
    125     return 0;
    126 }
    平面图最小割转对偶图最短路
  • 相关阅读:
    viewpager切换时底下的背景图标动画切换
    hdu 1594水题
    hdu 4256大水题
    hdu 1856并查集
    hdu4247水题
    hdu 4252单调栈
    hdu 4248排列问题
    hdu 1210
    hdu4245
    hdu 1593找规律题
  • 原文地址:https://www.cnblogs.com/Asm-Definer/p/4116387.html
Copyright © 2020-2023  润新知