zoukankan      html  css  js  c++  java
  • POJ

    (点击此处查看原题)

    题目分析

    题意:有n个人,编号记为1~n,n个人之间可能有人可以互相联系,如果A能和B联系,那么至少满足这两种情况之一:(1)A知道B的电话(2)A可以和C联系,并且C可以和B联系;

    因为某些人可能会丢失他的手机,导致他失去所有人的号码以及其他人手机中他的号码,也就是说这个人无法和任何人联系了;

    此时给出两个人s,t,问至少有多少人失去他们的手机,可以使得这两个人s,t无法联系。

    答案输出最少需要的人数以及失去手机的人的编号,如果存在多组解,输出字典序小的那一组。

     

    思路:平时写的最小割问题是求边割集,这个题题目求的是最小点割集,对于这类题目我们采用如下建边方法:

    1)将每个人代表的结点拆成两个结点,记编号1~n为入点,n+1~2*n为出点,由入点向出点建一条容量为1的边

    2)对于可以联系的两人 a,b,由a的出点向b的入点建一条容量为inf的边,并由b的出点向a的入点建一条容量为inf的边

    3)由于源点就是某个人,那么我们将这个人的出点当作源点

    建好边之后,我们跑一遍最大流(最小割)就可以得到最小点割集

    个人认为这个题主要麻烦在输出割点,我的方法是不断地的删点,如果删去这一点后得到的最大流大于删这点之前的最大流,那么这个点就是割点,为保证字典序最小,因而从1开始枚举割点

    代码区

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 998244353;
    const int Max = 1e5 + 10;
    const int Max2 = 1e3 + 10;
    
    struct Edge
    {
        int to, flow, next;
    } edge[Max << 1];
    
    int n, s, t;
    int head[Max2], tot;
    int dis[Max2];
    bool vis[210][210], cancel[210];
    int id[Max2], cnt;
    
    void init()
    {
        memset(head, -1, sizeof(head));tot = 0;
    }
    
    void add(int u, int v, int flow)
    {
        edge[tot].to = v;
        edge[tot].flow = flow;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    void build()
    {
        init();
        for (int i = 1; i <= n; i++)
        {
            if (!cancel[i])
            {
                add(i, i + n, 1);
                add(i + n, i, 0);
            }
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if(vis[i][j])
                {
                    add(i + n, j, inf);
                    add(j, i + n, 0);
                }
            }
        }
    }
    
    bool bfs()
    {
        memset(dis, -1, sizeof(dis));
        queue<int> q;
        q.push(s);
        dis[s] = 0;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to;
                if (edge[i].flow > 0 && dis[v] == -1)
                {
                    dis[v] = dis[u] + 1;
                    if (v == t)
                        return true;
                    q.push(v);
                }
            }
        }
        return false;
    }
    
    int dfs(int u, int flow_in)
    {
        if (u == t)
            return flow_in;
        int flow_out = 0;
        for (int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (edge[i].flow > 0 && dis[v] == dis[u] + 1)
            {
                int flow = dfs(v, min(flow_in, edge[i].flow));
                if (flow == 0)
                    continue;
                flow_in -= flow;
                flow_out += flow;
                edge[i].flow -= flow;
                edge[i ^ 1].flow += flow;
                if (flow_in == 0)
                    break;
            }
        }
        return flow_out;
    }
    
    int Dinic()
    {
        int sum = 0;
        while (bfs())
        {
            sum += dfs(s, inf);
        }
        return sum;
    }
    
    int main()
    {
    #ifdef LOCAL
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d%d", &n, &s, &t) != EOF)
        {
            memset(cancel, 0, sizeof(cancel));
            memset(vis, 0, sizeof(vis));
            cnt = 0;
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1,x; j <= n; j++)
                {
                    scanf("%d", &x);
                    vis[i][j] = x;
                }
            }
            if(vis[s][t])                   //s,t可以直接联系,那就不存在最小割了
            {
                printf("NO ANSWER!
    ");
                continue;
            }
            s += n;
            build();
            int min_cost = Dinic();
    
            printf("%d
    ", min_cost);
            if (min_cost == 0)
                continue;
            int last = min_cost;
            for (int i = 1; i <= n; i++)
            {
                if (i + n == s || i == t)
                    continue;
                cancel[i] = true;
                build();
                int temp = Dinic();
                if (temp < last)            //相比于不删除i点,删除i点之后最大流减少,则此点为割点
                {
                    id[++cnt] = i;
                    last--;
                    if (cnt == min_cost)
                        break;
                }
                else
                {
                    cancel[i] = false;
                }
            }
            for (int i = 1; i < cnt; i++)
                printf("%d ", id[i]);
            printf("%d
    ", id[cnt]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    PhotoshopCS6中文版图像处理实战从入门到精通
    Web安全开发指南
    OpenStack运维指南
    Word/Excel/PPT 2016高效办公实战从入门到精通
    UG NX 8.5中文版基础教程
    Moldflow 2018模流分析从入门到精通:升级版
    数据库与数据处理:Access 2010实现
    iOS开发网络数据之AFNetworking使用1
    AFNetworking2.5使用2
    iOS项目的完整重命名方法图文教程
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11384939.html
Copyright © 2011-2022 走看看