zoukankan      html  css  js  c++  java
  • BZOJ1001: [BeiJing2006]狼抓兔子(优化的dinic或转化对偶图求最短路)

    1001: [BeiJing2006]狼抓兔子

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 30078  Solved: 7908
    [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

    HINT

     2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

    Source

     
    [Submit][Status][Discuss]


    HOME Back

    题解1(网络流最大流dinic):

    题意是求一个无向图的最小割,然后我们运用最小割-最大流定理,可以转化成求最大流的问题。不过朴素的Dinic是会TLE的,这里提供一种优化方法:

    我们知道,假定在一次dinic过程中,发现不能再进行增广了,那么就相当于向下的这条路是废的。因此,我们可以直接把这条路堵上,然后就可以过了。

    参考代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 inline void read(int &x) 
     4 {
     5     x = 0; char c = getchar();
     6     while(!isdigit(c)) c = getchar();
     7     while(isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = getchar();
     8 }
     9 #define MAXN 1003
    10 struct node{
    11     int fr, to, va, nxt;
    12 }edge[MAXN * MAXN * 6];
    13 int head[MAXN * MAXN], cnt;
    14 inline void add_edge(int u, int v, int w) {
    15     edge[cnt].fr = u, edge[cnt].to = v, edge[cnt].va = w;
    16     edge[cnt].nxt = head[u], head[u] = cnt++;
    17     edge[cnt].fr = v, edge[cnt].to = u, edge[cnt].va = w;
    18     edge[cnt].nxt = head[v], head[v] = cnt++; //反向边初始化
    19 }
    20 int st, ed, rank[MAXN * MAXN];
    21 int BFS() {
    22     queue<int> q;
    23     memset(rank, 0, sizeof rank);
    24     rank[st] = 1;
    25     q.push(st);
    26     while(!q.empty()) {
    27         int tmp = q.front();
    28         //cout<<tmp<<endl;
    29         q.pop();
    30         for(int i = head[tmp]; i != -1; i = edge[i].nxt) {
    31             int o = edge[i].to;
    32             if(rank[o] || edge[i].va <= 0) continue;
    33             rank[o] = rank[tmp] + 1;
    34             q.push(o);
    35         }
    36     }
    37     return rank[ed];
    38 }
    39 int dfs(int u, int flow) {
    40     if(u == ed) return flow;
    41     int add = 0;
    42     for(int i = head[u]; i != -1 && add < flow; i = edge[i].nxt) {
    43         int v = edge[i].to;
    44         if(rank[v] != rank[u] + 1 || !edge[i].va) continue;
    45         int tmpadd = dfs(v, min(edge[i].va, flow - add));
    46         if(!tmpadd) {  //重要!就是这里!
    47             rank[v] = -1;
    48             continue;
    49         }
    50         edge[i].va -= tmpadd, edge[i ^ 1].va += tmpadd;
    51         add += tmpadd;
    52     }
    53     return add;
    54 }
    55 int ans;
    56 void dinic() {
    57     while(BFS()) ans += dfs(st, 0x3fffff); 
    58 }
    59 int n, m;
    60 inline int gethash(int i, int j) {
    61     return (i - 1) * m + j;
    62 }
    63 int main() {
    64     memset(head, -1, sizeof head);
    65     read(n), read(m);
    66     int tmp;
    67     st = 1, ed = gethash(n, m);
    68     for(int i = 1; i <= n; ++i) {
    69         for(int j = 1; j < m; ++j)
    70             read(tmp), add_edge(gethash(i, j), gethash(i, j + 1), tmp);
    71     }
    72     for(int i = 1; i < n; ++i) {
    73         for(int j = 1; j <= m; ++j) 
    74             read(tmp), add_edge(gethash(i, j), gethash(i + 1, j), tmp);
    75     }
    76     for(int i = 1; i < n; ++i) {
    77         for(int j = 1; j < m; ++j) 
    78             read(tmp), add_edge(gethash(i, j), gethash(i + 1, j + 1), tmp);
    79     }
    80     dinic();
    81     cout<<ans<<endl;
    82     return 0;
    83 } 
    View Code

    题解2(转化为对偶图求最短路):

    先来观察下面的这张图:

    我们发现,这么一张图,可以转化成任意两边的交点都在顶点上的形式。

    像这样任意两边的交点在顶点上的图我们称为平面图。

    几条边围成一个区域,这个区域称为一个面。

    对平面图,我们定义对偶图:

    下图中黑色的是个平面图,红色的就是对偶图。其建立方法是,对每个面建一个点,只要有一条边是在两个面之间,我们就对这两个面对应的点连边(稍有些绕)。注意是有一条边就连线。

    然后我们就得到萌萌哒的对偶图一张!

    对偶图就有很多美妙的性质了。比如说,我们发现,对偶图的一条边就对应了一条割边。

    既然如此的话,想想狼抓兔子,一条割边有一个容量,那么如果我们建它的对偶图,最短路就是最小割。

    所以得出下面的重要定理:

    对平面图来说,最大流 = 最小割 = 对偶图最短路

    所以我们就可以稳一些跑出来狼抓兔子。

    参考代码:

      1 //对偶图 
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 const int N=2000006;
      5 const int INF=0x3fffffff;
      6 int E=N*3;
      7 struct ARC {
      8     int u, val, next;
      9     inline void init(int a, int b, int c) {
     10         u=a, val=b, next=c;
     11     }
     12 } arc[E];
     13 int head[N], tot, S, T, n, m, dis[N];
     14 bool vs[N];
     15 
     16 struct data{
     17     int u, dis;
     18     data() {}
     19     data(int a, int b) : u(a), dis(b) {}
     20     bool operator < (const data &T) const {
     21         return dis>T.dis;
     22     }
     23 };
     24 
     25 inline void add_arc(int s, int t, int val) 
     26 {
     27     arc[tot].init(t, val, head[s]);
     28     head[s]=tot++;
     29 }
     30 
     31 priority_queue<data> Q;
     32 void Dijkstra() 
     33 {
     34     fill(dis, dis+T+1, INF);
     35     fill(vs, vs+T+1, 0);
     36     while(!Q.empty()) Q.pop();
     37     dis[S]=0, Q.push(data(S, 0));
     38     for(int u; !Q.empty(); ) 
     39     {
     40         u=Q.top().u, Q.pop();
     41         if(vs[u]) continue;
     42         if(u==T) 
     43         {
     44             printf("%d
    ", dis[T]);
     45             break;
     46         }
     47         vs[u]=1;
     48         for(int e=head[u]; e!=-1; e=arc[e].next) {
     49             int v=arc[e].u;
     50             if(vs[v] || dis[u]+arc[e].val>=dis[v]) continue;
     51             dis[v]=dis[u]+arc[e].val;
     52             Q.push(data(v, dis[v]));
     53         }
     54     }
     55 }
     56 
     57 void read(int &x) {
     58     char c;
     59     while((c=getchar())<'0' || c>'9');
     60     x=c-'0';
     61     while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
     62 }
     63 
     64 void Input() {
     65     for(int i=0, id1, id2, a; i<=n-1; i++)
     66         for(int j=1; j<=m-1; j++) {
     67             read(a);
     68             id1=((i-1)*(m-1)+j)*2-1;
     69             id2=(i*(m-1)+j)*2;
     70             if(i==0) id1=T;
     71             else if(i==n-1) id2=S;
     72             add_arc(id1,id2,a);
     73             add_arc(id2,id1,a);
     74         }
     75 
     76     for(int i=1, id1, id2, a; i<=n-1; i++)
     77         for(int j=0; j<m; j++) {
     78             read(a);
     79             id1=((i-1)*(m-1)+j)*2;
     80             id2=((i-1)*(m-1)+j+1)*2-1;
     81             if(j==0) id1=S;
     82             else if(j==m-1) id2=T;
     83             add_arc(id1, id2, a);
     84             add_arc(id2, id1, a);
     85         }
     86 
     87     for(int i=1, id1, id2, a; i<=n-1; i++)
     88         for(int j=1; j<=m-1; j++) {
     89             read(a);
     90             id1=((i-1)*(m-1)+j)*2;
     91             id2=((i-1)*(m-1)+j)*2-1;
     92             add_arc(id1, id2, a);
     93             add_arc(id2, id1, a);
     94         }
     95 }
     96 
     97 int main() {
     98     read(n), read(m);
     99     S=0, T=(n-1)*(m-1)*2+1;
    100     fill(head, head+T+1, -1), tot=0;
    101     if(n==1 || m==1) 
    102     {
    103         if(n>m) swap(n, m);
    104         int ans=INF;
    105         for(int i=1, a; i<m; i++) 
    106         {
    107             read(a);
    108             if(ans>a) ans=a;
    109         }
    110         printf("%d
    ", ans==INF?0:ans);
    111     }
    112     else Input(), Dijkstra();
    113     return 0;
    114 }
    View Code
  • 相关阅读:
    kafka-eagle监控kafka
    ZABBIX自动发现Redis端口并监控
    用Redislive监控redis
    zabbix监控hbase
    zabbix监控zookeeper
    zabbix监控nginx日志状态码
    深入理解JVM-内存溢出案例演示与分析
    深入理解JVM-hotspot虚拟机对象探秘
    java开发手册-总结与补充
    IntelliJ IDEA快速自动生成Junit测试类
  • 原文地址:https://www.cnblogs.com/csushl/p/10080486.html
Copyright © 2011-2022 走看看