bzoj1001 [ICPC-Beijing 2006]狼抓兔子

我满心以为本题正解为最短路,结果到处都是最大流……

几乎所有的都写了什么“对偶图”跑最短路~~,但我真的不知道什么叫做对偶图~~
-------------------------------------------------------------------------------------------------
介绍一下本题的最短路算法叭。并不算难。主要是感性理解。

首先很容易观察出这是一个最小割,那么就是求最大流了。

但是这题的点数高达10e6,按常理来说最大流应该稳稳地TLE。但是没有T好气哦

那么想办法!

首先最小割在本题时可以这样感性理解:上图是一个你同学在钢铁厂打出来的一个铁架子。你把start处用手捏起来,end处自然垂下。用一个剪刀钳把这个铁架子拦腰剪成两半。

如果剪成好几瓣(掉下来有好几个联通块的),那么显而易见,不如剪成两半(把刚才几个剪断的地方原样拼起来变成两个联通块)。

我们把三角形看成是点,黑色的边看成是连接三角形的边,那么剪成两半的意思是……在三角形点的图上找一条从左下到右上的最短路径!沿着这条路径剪开就行了。

但是这题的点数高达10e6,按常理来说SPFA应该稳稳地TLE。但是没有T好气哦

那就堆优化dijkstra。

这个加边超烦的。但思路清晰的话就没什么问题。记得在左下空白处设一个源点,右上角设一个汇点。源点连接所有邻接它的左边的、下边的三角形点,汇点连接所有邻接它的右边的、上边的三角形点。

#include <cstdio>
#include <queue>
using namespace std;
const int N=1002,S=N*N*6+30,inf=(1<<30)-1;
int n,m,a[N][N],b[N][N],c[N][N],d[S],id[N][N],ss,tt,h[S],v[S],nx[S],w[S],eg=1;
bool vis[S]={0};
struct info
{
    int x,w;
}data;
inline bool operator<(const info &a,const info &b)
{
    return a.w>b.w;
}
priority_queue<struct info> pq;
inline void egadd(int uu,int vv,int ww)
{
    nx[++eg]=h[uu];h[uu]=eg;
    v[eg]=vv;w[eg]=ww;
}
void rd(int &s)
{
    s=0;char c=getchar();
    while (c<48) c=getchar();
    while (c>=48) s=(s<<1)+(s<<3)+(c^48),c=getchar();
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m-1;j++)
            rd(a[i][j]);
    for (int i=1;i<=n-1;i++)
        for (int j=1;j<=m;j++)
            rd(b[i][j]);
    for (int i=1;i<=n-1;i++)
        for (int j=1;j<=m-1;j++)
            rd(c[i][j]);
    n--;m--;
    if (!n)
    {
        int res=inf;
        for (int i=1;i<=m;i++)
            if (a[1][i]<res)
                res=a[1][i];
        printf("%d",res);
        return 0;
    }
    if (!m)
    {
        int res=inf;
        for (int i=1;i<=n;i++)
            if (b[i][1]<res)
                res=b[i][1];
        printf("%d",res);
        return 0;
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            id[i][j]=(i-1)*2*m+j;
    ss=n*2*m+1;tt=ss+1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            egadd(id[i][j],id[i][j]+m,c[i][j]);
            egadd(id[i][j]+m,id[i][j],c[i][j]);
        }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m-1;j++)
        {
            egadd(id[i][j],id[i][j+1]+m,b[i][j+1]);
            egadd(id[i][j+1]+m,id[i][j],b[i][j+1]);
        }
    for (int i=1;i<=n-1;i++)
        for (int j=1;j<=m;j++)
        {
            egadd(id[i][j]+m,id[i+1][j],a[i+1][j]);
            egadd(id[i+1][j],id[i][j]+m,a[i+1][j]);
        }
    for (int i=1;i<=m;i++)
    {
        egadd(id[1][i],tt,a[1][i]);
        egadd(ss,id[n][i]+m,a[n+1][i]);
    }
    for (int i=1;i<=n;i++)
    {
        egadd(ss,id[i][1]+m,b[i][1]);
        egadd(id[i][m],tt,b[i][m+1]);
    }
    for (int i=1;i<=tt;i++)
        d[i]=inf;
    d[ss]=0;
    pq.push((info){ss,0});
    while (!pq.empty())
    {
        while (!pq.empty() && vis[pq.top().x])
            pq.pop();
        if (pq.empty()) break;
        data=pq.top();
        pq.pop();
        int x=data.x,ww=data.w;
        printf("%d %d\n",x,ww);
        vis[x]=true;
        for (int i=h[x];i;i=nx[i])
            if (!vis[v[i]] && d[v[i]]>ww+w[i])
            {
                d[v[i]]=ww+w[i];
                pq.push((info){v[i],d[v[i]]});
                printf("Add:%d %d\n",v[i],d[v[i]]);
            }
    }
    printf("%d",d[tt]);
    return 0;
}

原文地址:https://www.cnblogs.com/Algebra-hy/p/10376460.html

时间: 2024-10-25 06:03:17

bzoj1001 [ICPC-Beijing 2006]狼抓兔子的相关文章

BZOJ 1001 Beijing 2006 狼抓兔子 最小割

题目大意:有一张无向图,描述的是兔子窝的位置和之间的边.现在狼来抓兔子了,兔子慌忙的从(1,1)逃走到(m,n).每条边上都有能通过最多的兔子数量.狼不想让兔子逃走,每在一条边驻守一只狼就可以避免一个兔子通过.问最少多少狼可以让所有兔子都不能逃走. 思路:建图,按题目中的意思是去掉最小的边使得源到汇不连通,显然的最小割. CODE: #include <queue> #include <cstdio> #include <cstring> #include <io

BZOJ 1001 [BJOI 2006] 狼抓兔子

BZOJ题面 瑾以此题纪念博主迈出冲刺省选的第一步 打眼一看,这不是裸的最小割吗? 最小割 == 最大流: 然后 5 分钟码完 ISAP : 交上去一看......TLE......懵逼...... 然后进行了一波没有卵用的优化常数...... (去他妈的 1e6 个点,3e6 条边!!!) 问了问度娘,才知道这题的图是 '平面图' : 平面图的最小割和最大流可以通过将其转换成对偶图跑最短路求解:(涨姿势) 那么什么是对偶图呢? 通俗的讲,对偶图就是把原图的点换成面(边围成的区域),面换成点,而

解题:BJOI 2006 狼抓兔子

题面 可以看出来是最小割,然后你就去求最大流了 这么大的范围就是让你用网络流卡的?咋想的啊=.=??? 建议还是老老实实用 平面图最小割等于其对偶图最短路 这个东西来做吧,虽然这个东西跑的也挺慢的,最后一个点跑了$2s$ 对偶图就是被边分割出来的每个区域当成一个点,然后两个区域有公共边就连边,起点和终点的问题就在源汇点中间连一条边然后就能分出来了 1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #inc

ICPC-Beijing 2006 狼抓兔子

题目描述 题解: 裸的最小割. 但是最大流跑不过去怎么办? 转变一下,既然最大流是一条左下<->右上的通路,我们可以把图划分为若干区域, 最后找左下到右上的最短路就行了. 代码: #include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 1100; t

Luogu P4001 [ICPC-Beijing 2006]狼抓兔子

Link 平面图的最小割等于其对偶图的最短路. 虽然我不会证但感觉确实挺好理解的. #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstring> #include<utility> #include<functional> #define pi pair<int,int> #define fi first

bzoj1001 [BeiJing2006]狼抓兔子

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23723  Solved: 5981[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

【bzoj1001】【狼抓兔子】

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MB Submit: 12719 Solved: 3017 [Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=

BZOJ1001: [BeiJing2006]狼抓兔子【最短路】

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1001 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 27684  Solved: 7127 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的

BZOJ 1001: [BeiJing2006]狼抓兔子 对偶图

本题是最大流转最小割转对偶图最短路 推荐周东的<浅析最大最小定理在信息学竞赛中的应用> 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 12166  Solved: 2866 [Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在