P4001 [BJOI2006]狼抓兔子

网络流快乐地跑。。。



这道题就是要求这个无向图的最小割。

根据最小割最大流定理,我们求个最大流就好了。

但是数据巨大。一百万个点,我们看上去就有2996001条边。

这个时候,如果按照网络流做法,建反向边的话,需要11984004条边,MLE。

其实我就没做过无向图的网络流。。。

结论:无向图网络流,只要两条边捆绑在一起就可以了,互相为反向边。

为什么有向图的时候反向边边权为0,而这里不为0?

无向图有两条边,你必须加上去。有向图压根就没有这条边,只是给你一个反悔的机会而已,是个中介的边。

所以建上5992002条边,跑一个有当前弧优化的dinic,直接完成。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1000005, INF = 0x7f7f7f7f;
struct Edges
{
    int next, to, weight;
} e[maxn * 12];
int head[maxn], tot = 1;
int n, m, s, t;
int dep[maxn];
int cur[maxn];
int queue[maxn << 1], front, rear;
int id(int x, int y)
{
    return (y - 1) * m + x;
}
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘)
    {
        if(ch == ‘-‘) s = -1;
        ch = getchar();
    }
    while(ch >= ‘0‘ && ch <= ‘9‘)
    {
        ans = ans * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return s * ans;
}
void link(int u, int v, int w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
void addEdges(int u, int v, int w)
{
    link(u, v, w); link(v, u, 0);
    link(v, u, w); link(u, v, 0);
}
bool bfs()
{
    memset(dep, 0, sizeof(dep));
    front = rear = 0;
    dep[s] = 1; queue[rear++] = s;
    while(front < rear)
    {
        int u = queue[front++];
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dep[v] && e[i].weight > 0)
            {
                dep[v] = dep[u] + 1;
                queue[rear++] = v;
            }
        }
    }
    return dep[t];
}
int dfs(int u, int flow)
{
    if(u == t) return flow;
    for(int &i = cur[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(dep[v] == dep[u] + 1 && e[i].weight > 0)
        {
            int di = dfs(v, std::min(flow, e[i].weight));
            if(di > 0)
            {
                e[i].weight -= di;
                e[i ^ 1].weight += di;
                return di;
            }
        }
    }
    return 0;
}
int dinic()
{
    int ans = 0;
    while(bfs())
    {
        for(int i = 1; i <= t; i++) cur[i] = head[i];
        while(int temp = dfs(s, INF)) ans += temp;
    }
    return ans;
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j < m; j++)
        {
            int weight = read();
            //printf("%d %d\n", id(j, i), id(j + 1, i));
            addEdges(id(j, i), id(j + 1, i), weight);
        }
    }
    for(int i = 1; i < n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            int weight = read();
            //printf("%d %d\n", id(j, i), id(j, i + 1));
            addEdges(id(j, i), id(j, i + 1), weight);
        }
    }
    for(int i = 1; i < n; i++)
    {
        for(int j = 1; j < m; j++)
        {
            int weight = read();
            //printf("%d %d\n", id(j, i), id(j + 1, i + 1));
            addEdges(id(j, i), id(j + 1, i + 1), weight);
        }
    }
    s = 1; t = n * m;
    printf("%d\n", dinic());
    return 0;
}

原文地址:https://www.cnblogs.com/Garen-Wang/p/9362849.html

时间: 2024-08-01 16:01:06

P4001 [BJOI2006]狼抓兔子的相关文章

BJOI2006狼抓兔子

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

[BJOI2006]狼抓兔子 暴力AC啦!

直接暴力建边,在lougu上跑的飞快.(except the last test) 总结一下也就是三句话: insert(id(i, j), id(i, j + 1), x) insert(id(i, j), id(i + 1, j), x) insert(id(i, j), id(i + 1, j + 1), x) 没了就,..dinic什么的就看看本博客分享的总结爸... 代码当然还是要发的,即使只是一个暴力.. 1 #include <map> 2 #include <set>

BZOJ1001 BJOI2006 狼抓兔子

Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是

[BJOI2006]狼抓兔子(网络流)

题目描述 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上

[BJOI2006]狼抓兔子

思路: 求网格图的最小割.然而网格图的边数比较多,直接用EdmondsKarp算法会TLE(据说用Dinic或ISAP可以过),解决的方法是将网格图的最小割转化成其对偶图的最短路,设图的左下端为起点,右上端为重点,然后跑一遍Dijkstra即可.注意要特判$n=1$或$m=1$的情况,另外因为每个方格实际上是会被斜线分成两个三角,所以点数要开两倍$n^2$,也就是$2\times10^6$. 1 #include<cstdio> 2 #include<cctype> 3 #incl

P2030 - 【BJOI2006】狼抓兔子

P2030 - [BJOI2006]狼抓兔子 Description 八中OJ上本题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>

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

【BZOJ】1001: [BeiJing2006]狼抓兔子

1001: [BeiJing2006]狼抓兔子 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)的窝中去,狼王开始伏击

BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

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