码迷,mamicode.com
首页 > 其他好文 > 详细

USACO 5.4.3 点的最小割

时间:2016-02-08 21:15:04      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:

  这道题的难点在于将点拆分, 无向图变为有向图, 对于 i点我们可以将这个点拆分成2*i-1 -> 2*i,权值为1 对于i - j, 我们可以将点拆分以后再添加2*j -> 2*i-1 2*i -> 2*j-1,权值为inf,  然后求解最大流即为要去掉的顶点的个数, 求解具体的边的时候我们可以枚举要删除的边, 假设删除前的最大流为f,边权为1, 删除边后的最大流为ff, 若ff+1 == f的话那么这条边就在最小割集中。然后更新最大流,删掉最这条边重复上述操作即可, 代码如下:

/*
    ID: m1500293
    LANG: C++
    PROG: telecow
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int maxn = 250;
int inf = 0x3f3f3f3f;
struct Dinic
{
    int n;   //n个顶点
    struct edge { int from, to, cap; };
    vector<int> G[maxn];
    vector<edge> e;
    int level[maxn], iter[maxn];
    void init()
    {
        for(int i=0; i<=n; i++)
            G[i].clear();
        e.clear();
    }
    void add_edge(int u, int v, int cap)
    {
        e.push_back((edge){u, v, cap});
        e.push_back((edge){v, u, 0});
        int m = e.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
    }
    void bfs(int s)
    {
        memset(level, -1, sizeof(level));
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            for(int i=0; i<G[u].size(); i++)
            {
                edge &te = e[G[u][i]];
                if(te.cap>0 && level[te.to]<0)
                {
                    level[te.to] = level[u] + 1;
                    que.push(te.to);
                }
            }
        }
    }
    int dfs(int v, int t, int f)
    {
        if(v == t) return f;
        for(int &i=iter[v]; i<G[v].size(); i++)
        {
            edge &tpe = e[G[v][i]];
            if(tpe.cap>0 && level[v]<level[tpe.to])
            {
                int d = dfs(tpe.to, t, min(f, tpe.cap));
                if(d > 0)
                {
                    tpe.cap -= d;
                    e[G[v][i]^1].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int max_flow(int s, int t)
    {
        int flow = 0;
        for(;;)
        {
            bfs(s);
            if(level[t]<0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f=dfs(s, t, 0x3fffffff)>0))
                flow += f;
        }
    }
}aa, bb;
bool cmp(const int &a, const int &b)
{
    return a < b;
}
int ans[200], nans;
int main()
{
    freopen("telecow.in", "r", stdin);
    freopen("telecow.out", "w", stdout);
    int N, M, c1, c2;
    scanf("%d%d%d%d", &N, &M, &c1, &c2);
    aa.n = 2*N;
    aa.init();

    for(int i=0; i<M; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        aa.add_edge(2*u, 2*v-1, inf);
        aa.add_edge(2*v, 2*u-1, inf);
//        aa.add_edge(2*u-1, 2*u, 1);
//        aa.add_edge(2*v-1, 2*v, 1);           //会导致重复添加一条边
    }
    for(int i=1; i<=N; i++)
        aa.add_edge(2*i-1, 2*i, 1);
    //printf("%d\n", aa.max_flow(2*c1, 2*c2-1));
    bb = aa;
    int f = bb.max_flow(2*c1, 2*c2-1);
    int ans1 = f;
    nans = 0;
    for(int i=0; i<aa.e.size(); i++) if(aa.e[i].cap == 1)
    {
        bb = aa;
        bb.e[i].cap = 0;
        int ff = bb.max_flow(2*c1, 2*c2-1);
        if(ff+1 == f)   //这条边在最小割中
        {
            ans[nans++] = bb.e[i].to/2;
            f -= 1;    //更新最大流
            aa.e[i].cap = 0;    //删掉这条边
        }
    }
    sort(ans, ans+nans, cmp);
    printf("%d\n", ans1);
    for(int i=0; i<nans; i++)
        printf("%d%c", ans[i], i==nans-1?\n: );
    return 0;
}

 

USACO 5.4.3 点的最小割

标签:

原文地址:http://www.cnblogs.com/xingxing1024/p/5185088.html

(0)
(2)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!