1. 程式人生 > >P4001 [BJOI2006]狼抓兔子

P4001 [BJOI2006]狼抓兔子

反向 什麽 最小割 char turn bool 完成 如果 void

網絡流快樂地跑。。。


這道題就是要求這個無向圖的最小割。

根據最小割最大流定理,我們求個最大流就好了。

但是數據巨大。一百萬個點,我們看上去就有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;
}

P4001 [BJOI2006]狼抓兔子