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;
}

posted @ 2018-07-24 21:47  Garen-Wang  阅读(175)  评论(0编辑  收藏  举报