zoukankan      html  css  js  c++  java
  • BZOJ1001 [BeiJing2006]狼抓兔子 平面图转对偶图,最小割转最短路

    1001: [BeiJing2006]狼抓兔子

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 28885  Solved: 7540
    [Submit][Status][Discuss]

    Description

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

     

    左上角点为(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

     很容易可以看出这是一道求最小割的题,但图太大了网络流没法跑。网上有人网络流水过的,但我写的网络流莫名奇妙一直WA...

      1 /**************************************************************
      2     Problem: 1001
      3     User: mizersy
      4     Language: C++
      5     Result: Wrong_Answer
      6 ****************************************************************/
      7  
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 const int MAXN = 2000010;
     11 const int MAXM = 6200010;
     12 const int INF = 0x3f3f3f3f;
     13 struct Edge{
     14     int to,next,cap,flow;
     15 } edge[MAXM];
     16 int tol;
     17 int head[MAXN];
     18 void init(){
     19     tol = 2;
     20     memset(head,-1,sizeof(head));
     21 }
     22 void addedge(int u,int v,int w,int rw = 0){
     23     edge[tol].to = v;
     24     edge[tol].cap = w;
     25     edge[tol].flow = 0;
     26     edge[tol].next = head[u];
     27     head[u] = tol++;
     28     edge[tol].to = u;
     29     edge[tol].cap = rw;
     30     edge[tol].flow = 0;
     31     edge[tol].next = head[v];
     32     head[v] = tol++;
     33 }
     34 int Q[MAXN];
     35 int dep[MAXN],cur[MAXN],sta[MAXN];
     36 bool bfs(int s,int t,int n){
     37     int front = 0,tail = 0;
     38     memset(dep,-1,sizeof(dep[0])*(n+1));
     39     dep[s] = 0;
     40     Q[tail++] = s;
     41     while(front < tail){
     42         int u = Q[front++];
     43         for(int i = head[u]; i !=-1; i = edge[i].next){
     44             int v = edge[i].to;
     45             if(edge[i].cap > edge[i].flow && dep[v] ==-1){
     46                 dep[v] = dep[u] + 1;
     47                 if(v == t)
     48                     return true;
     49                 Q[tail++] = v;
     50             }
     51         }
     52     }
     53     return false;
     54 }
     55 int dinic(int s,int t,int n){
     56     int maxflow = 0;
     57     while(bfs(s,t,n)){
     58         for(int i = 0; i <= n; i++) cur[i] = head[i];
     59         int u = s, tail = 0;
     60         while(cur[s] !=-1){
     61             if(u == t){
     62                 int tp = INF;
     63                 for(int i = tail-1; i >= 0; i--)
     64                     tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
     65                 maxflow += tp;
     66                 for(int i = tail-1; i >= 0; i--){
     67                     edge[sta[i]].flow += tp;
     68                     edge[sta[i]^1].flow-= tp;
     69                     if(edge[sta[i]].cap-edge[sta[i]].flow == 0)
     70                         tail = i;
     71                 }
     72                 u = edge[sta[tail]^1].to;
     73             }else if(cur[u] !=-1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to])
     74             {
     75                 sta[tail++] = cur[u];
     76                 u = edge[cur[u]].to;
     77             }else{
     78                 while(u != s && cur[u] ==-1)
     79                     u = edge[sta[--tail]^1].to;
     80                 cur[u] = edge[cur[u]].next;
     81             }
     82         }
     83     }
     84     return maxflow;
     85 }
     86 int n,m,cnt;
     87 int a[1005][1005];
     88  
     89 int point(int i,int j){
     90     return (i-1)*m+j;
     91 }
     92  
     93 int main(){
     94     scanf("%d%d",&n,&m);
     95     cnt = 0;
     96     init();
     97     memset(a,0,sizeof(a));
     98     for (int i = 1;i <= n;++i){
     99         for (int j = 1;j < m;++j){
    100             int w; scanf("%d",&w);
    101             addedge(point(i,j),point(i,j+1),w);
    102         }
    103     }
    104     for (int i = 1;i < n;++i){
    105         for (int j = 1;j <= m;++j){
    106             int w; scanf("%d",&w);
    107             addedge(point(i,j),point(i+1,j),w);
    108         }
    109     }
    110     for (int i = 1;i < n;++i){
    111         for (int j = 1;j < m;++j){
    112             int w; scanf("%d",&w);
    113             addedge(point(i,j),point(i+1,j+1),w);
    114         }
    115     }
    116     printf("%d
    ",dinic(1,n*m,n*m));
    117 }
    View Code

    查了题解说因为图是平面图,所以可以把平面图转对偶图,然后对偶图的最短路就是平面图的最小割,惊了。 上学期离散课上学过平面图转对偶图,但是课时比较赶老师就讲的很水,当时没觉得这东西有什么用然后就没深入研究   想不到转对偶图居然还有这种妙用,不过想一下也很容易理解

    对偶图建图的时候需要小心一点,写的时候调了半天..

      1 /**************************************************************
      2     Problem: 1001
      3     User: mizersy
      4     Language: C++
      5     Result: Accepted
      6     Time:3108 ms
      7     Memory:118480 kb
      8 ****************************************************************/
      9  
     10 #include <bits/stdc++.h>
     11 using namespace std;
     12 const int MAXN = 2000005;
     13 struct Edge{int to,next,w;}edge[MAXN*4];
     14 int tol,n,m,w;
     15 int head[MAXN],vis[MAXN],dis[MAXN];
     16 void init(){
     17     tol = 0;
     18     memset(vis,0,sizeof(vis));
     19     memset(dis,0x3f3f3f3f,sizeof(dis));
     20     memset(head,-1,sizeof(head));
     21 }
     22  
     23 void addedge(int u,int v,int w){
     24     edge[tol] = Edge{v,head[u],w};
     25     head[u] = tol++;
     26     edge[tol] = Edge{u,head[v],w};
     27     head[v] = tol++;
     28 }
     29  
     30 void getmap(){
     31     for (int j = 1;j < m;++j){
     32         scanf("%d",&w);
     33         addedge(0,j*2,w);
     34     }
     35     for (int i = 2;i < n;++i){
     36         for (int j = 1;j < m;++j){
     37             scanf("%d",&w);
     38             addedge(2*(i-2)*(m-1)+j*2-1,2*(i-1)*(m-1)+j*2,w);
     39         }
     40     }
     41     if (n >= 2)
     42     for (int j = 1;j < m;++j){
     43         scanf("%d",&w);
     44         addedge(2*(n-2)*(m-1)+j*2-1,2*(n-1)*(m-1)+1,w);
     45     }
     46     for (int i = 1;i < n;++i){
     47         for (int j = 1;j <= m;++j){
     48             scanf("%d",&w);
     49             if (j == 1) addedge(2*(n-1)*(m-1)+1,2*(i-1)*(m-1)+1,w);
     50             else if (j == m) addedge(2*i*(m-1),0,w);
     51             else addedge(2*(i-1)*(m-1)+(j-1)*2,2*(i-1)*(m-1)+(j-1)*2+1,w);
     52         }
     53     }
     54  
     55     for (int i = 1;i < n;++i){
     56         for (int j = 1;j < m;++j){
     57             scanf("%d",&w);
     58             addedge(2*(i-1)*(m-1)+(j-1)*2+1,2*(i-1)*(m-1)+j*2,w);
     59         }
     60     }
     61 }
     62  
     63 int spfa(int s,int t){
     64     queue <int> q;
     65     dis[s] = 0; vis[s] = 1;
     66     q.push(s);
     67     while(!q.empty()){
     68         int u = q.front(); q.pop();
     69         vis[u] = 0;
     70         for (int i = head[u];i != -1;i = edge[i].next){
     71             int v = edge[i].to,w = edge[i].w;
     72             if (dis[v] > dis[u] + w){
     73                 dis[v] = dis[u] + w;
     74                 if (!vis[v]){
     75                     vis[v] = 1;
     76                     q.push(v);
     77                 }
     78             }
     79         }
     80     }
     81     return dis[t];
     82 }
     83  
     84 int main(){
     85     init();
     86     scanf("%d%d",&n,&m);
     87     if (n == 1 || m == 1){
     88         if (n > m) swap(n,m);
     89         int ans = 0x3f3f3f3f;
     90         for (int i = 1;i < m;++i){
     91             scanf("%d",&w);
     92             ans = min(ans,w);
     93         }
     94         if (ans == 0x3f3f3f3f) ans = 0;
     95         printf("%d
    ",ans);
     96         return 0;
     97     }
     98     getmap();
     99     printf("%d
    ",spfa(0,2*(m-1)*(n-1)+1));
    100     return 0;
    101 }
  • 相关阅读:
    bzoj1015星球大战(并查集+离线)
    bzoj1085骑士精神(搜索)
    bzoj1051受欢迎的牛(Tarjan)
    左偏树学习
    hdu1512 Monkey King(并查集,左偏堆)
    左偏树(模板)
    PAT (Basic Level) Practice (中文) 1079 延迟的回文数 (20分) (大数加法)
    PAT (Basic Level) Practice (中文) 1078 字符串压缩与解压 (20分) (字符转数字——栈存放)
    PAT (Basic Level) Practice (中文) 1077 互评成绩计算 (20分) (四舍五入保留整数)
    PAT (Basic Level) Practice (中文) 1076 Wifi密码 (15分)
  • 原文地址:https://www.cnblogs.com/mizersy/p/9564647.html
Copyright © 2011-2022 走看看