zoukankan      html  css  js  c++  java
  • bzoj1001 [BeiJing2006]狼抓兔子

    1001: [BeiJing2006]狼抓兔子

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 27126  Solved: 6933
    [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新加数据一组,可能会卡掉从前可以过的程序。

    分析:终于过了1001题!

      这道题如果用最大流+优化也能过,但不是最优解.

      注意这是一个平面图,平面图就是两条边的交点只会出现在顶点处.  平面图的最小割实际上就是对偶图两个对称点的最短路!

      ,如果两个平面之间有边,就将对应的两个平面连起来,边权为这两个平面之间的边的边权. 添加两个点1,N. 和图内部的平面连边.

       最后求出1~N的最短路即可.

       平面的编号有点麻烦. 我的代码是从上到下从左到右从2开始编号的,一个不容易错的思考方法:将点的下标看作是格子的下标,每一个格子里有两个平面,找找规律就行了.

       注意边数的计算! 一个平面最多会向外连3条边,算上反向边,就有6条边.那么数组大小就要开到600w.

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1010,inf = 0x7fffffff;
    int n,m,heng[maxn][maxn],shu[maxn][maxn],xie[maxn][maxn],N;
    int head[maxn * maxn * 2 + 10],to[6000010],nextt[6000010],tot = 1;
    int d[maxn * maxn * 2 + 10],vis[maxn * maxn * 2 + 10],w[6000010];
    
    void add(int x,int y,int z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void spfa()
    {
        memset(d,127/3,sizeof(d));
        queue <int> q;
        q.push(1);
        d[1] = 0;
        vis[1] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for (int i = head[u];i;i = nextt[i])
            {
                int v = to[i];
                if (d[v] > d[u] + w[i])
                {
                    d[v] = d[u] + w[i];
                    if(!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    void pre()
    {
        N = (n - 1) * (m - 1) * 2 + 2;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j < m; j++)
                scanf("%d",&heng[i][j]);
        for (int i = 1; i < n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d",&shu[i][j]);
        for (int i = 1; i < n; i++)
            for (int j = 1; j < m; j++)
                scanf("%d",&xie[i][j]);
    }
    
    void solve()
    {
        pre();
        for (int i = 1; i < n; i++)
            for (int j = 1; j < m; j++)
            {
                int temp = (i - 1) * (m - 1) + j;
                add(temp * 2,temp * 2 + 1,xie[i][j]);
                add(temp * 2 + 1,temp * 2,xie[i][j]);
                if (j != 1)
                {
                    add(temp * 2 - 1,temp * 2,shu[i][j]);
                    add(temp * 2,temp * 2 - 1,shu[i][j]);
                }
                if (i != 1)
                {
                    int temp2 = (temp - m + 1);
                    add(temp * 2 + 1,temp2 * 2,heng[i][j]);
                    add(temp2 * 2,temp * 2 + 1,heng[i][j]);
                }
            }
        for (int i = 1; i < n; i++)
        {
            int temp = (i - 1) * (m - 1) + 1;
            add(1,temp * 2,shu[i][1]);
            add(temp * 2,1,shu[i][1]);
            temp = 2 * i * (m - 1) + 1;
            add(N,temp,shu[i][m]);
            add(temp,N,shu[i][m]);
        }
        for (int i = 1; i < m; i++)
        {
            int temp = i * 2 + 1;
            add(temp,N,heng[1][i]);
            add(N,temp,heng[1][i]);
            temp = (n - 2) * (m - 1) + i;
            add(temp * 2,1,heng[n][i]);
            add(1,temp * 2,heng[n][i]);
        }
        spfa();
        printf("%d
    ",d[N]);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        if (n == 1 && m == 1)
            printf("%d
    ",0);
        else
            if (n == 1 || m == 1)
        {
            if (n == 1)
            {
                int minn = inf;
                for (int i = 1; i < m; i++)
                {
                    int x;
                    scanf("%d",&x);
                    minn = min(minn,x);
                }
                printf("%d
    ",minn);
            }
            else
            {
                int minn = inf;
                for (int i = 1; i < n; i++)
                {
                    int x;
                    scanf("%d",&x);
                    minn = min(minn,x);
                }
                printf("%d
    ",minn);
            }
        }
        else
            solve();
    
        return 0;
    }
  • 相关阅读:
    Android NDK 学习之传递类对象
    https://www.aminer.cn/ AI研究
    MYSQL 的一些文件及说明
    Windows下移动MariaDB数据目录 (转!)
    MariaDB Galera Cluster 10.1 只支持 LINUX ?!
    MARIADB 在 OPENSUSE 的安装。
    “命令行程序”的通用图形界面 (转)
    代码生成的地址:mygeneration
    上海力软--快速开发框架
    康力优蓝机器人 -- 优友U05类人型机器人发布
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8591576.html
Copyright © 2011-2022 走看看