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 }
  • 相关阅读:
    JAVA 关键字
    github 上传代码到仓库

    创建链表及使用
    关于MAP文件的使用(转贴)
    styledcomponent使用(一)
    关于EDM模型中多个实体之间循环引用导致保存数据失败的解决方案一例
    C#格式化字符串
    [原]存取AVD设备SD卡中的文件
    NSStirng、NSArray、以及枚举(Method小集合)
  • 原文地址:https://www.cnblogs.com/mizersy/p/9564647.html
Copyright © 2011-2022 走看看