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\n",d[N]);
}

int main()
{
    scanf("%d%d",&n,&m);
    if (n == 1 && m == 1)
        printf("%d\n",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\n",minn);
        }
        else
        {
            int minn = inf;
            for (int i = 1; i < n; i++)
            {
                int x;
                scanf("%d",&x);
                minn = min(minn,x);
            }
            printf("%d\n",minn);
        }
    }
    else
        solve();

    return 0;
}

 

 

 

 

posted @ 2018-03-17 17:49  zbtrs  阅读(194)  评论(0编辑  收藏  举报