• 【USACO 5.4.3】TeleCowmunication


    题目大意

      给一幅由N个点和M条无向边组成的图,要求删掉最少的点使得c1和c2无法连通(不能删这两个点)。输出删的点数以及要删的点,要求删的点的字典序最小。

    题解

      我记得以前貌似是删边的。删点其实也类似,把点转换成边就可以了。所以就要拆点了,拆点的方法不多说。

      然后跑一遍最小割(最大流),原来的边的流量设为无限大,拆点的边就置为1,不过要注意的是这里是无向边。

      主要问题就是怎么让答案的字典序最小。其实枚举就行了!枚举每一个点,然后删点,跑最大流,看一下流量是否变小,变小了就真(是真的!)删掉这个点,如果没有改变说明删不删这个点都一样。

      因为每次增广都肯定会少掉至少一条边(点),这里的求最大流速度就会很快,大概是O(N2),那么总的时间复杂度就是O(N3)。

    代码

    /*
    TASK:telecow
    LANG:C++
    */
    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    const int INF = 0x7fffffff;
    
    struct Edge
    {
        int c, f;
        bool canget;
        
        Edge() {
            canget = false;
        }
        
        Edge(int cap, int flow) : c(cap), f(flow) {
            canget = true;
        }
        
    }net[205][205];
    
    int n, m, c1, c2, netflow, d[205], side[605][2];
    
    bool BFS()
    {
        memset(d, 0, sizeof(d));
        d[2 * c1] = 1;
        queue<int> Q;
        Q.push(2 * c1);
        while (!Q.empty())
        {
            int x = Q.front();
            Q.pop();
            for (int i = 1; i <= 2 * n; ++i)
                if (d[i] == 0 && net[x][i].canget && net[x][i].f < net[x][i].c)
                {
                    d[i] = d[x] + 1;
                    Q.push(i);
                }
        }
        return d[2 * c2 - 1];
    }
    
    int DFS(int x, int a)
    {
        if (x == 2 * c2 - 1 || a == 0) return a;
        int flow = 0;
        for (int i = 1; i <= 2 * n; ++i)
        {
            int fw;
            if (d[x] + 1 == d[i] && (fw = DFS(i, min(a, net[x][i].c - net[x][i].f))) > 0)
            {
                net[x][i].f += fw;
                net[i][x].f -= fw;
                flow += fw;
                a -= fw;
            }
            if (a == 0) break;
        }
        return flow;
    }
    
    int main()
    {
        freopen("telecow.in", "r", stdin);
        freopen("telecow.out", "w", stdout);
        scanf("%d%d%d%d", &n, &m, &c1, &c2);
        for (int i = 1; i <= n; ++i)
        {
            net[2 * i - 1][2 * i] = Edge(1, 0);
            net[2 * i][2 * i - 1] = Edge(0, -1);
        }
        for (int i = 0; i < m; ++i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            side[i][0] = a;
            side[i][1] = b;
            net[2 * a][2 * b - 1] = Edge(INF, 0);
            net[2 * b - 1][2 * a] = Edge(0, 0);
            net[2 * b][2 * a - 1] = Edge(INF, 0);
            net[2 * a - 1][2 * b] = Edge(0, 0);
        }
        netflow = 0;
        net[2 * c1 - 1][2 * c1].canget = net[2 * c1][2 * c1 - 1].canget = false;
        net[2 * c2 - 1][2 * c2].canget = net[2 * c2][2 * c2 - 1].canget = false;
        while (BFS())
        {
            netflow += DFS(2 * c1, INF);
        }
        printf("%d
    ", netflow);
        for (int k = 1; k <= n; ++k)
        {
            if (k == c1 || k == c2) continue;
            for (int i = 1; i <= n; ++i)
            if (net[2 * i - 1][2 * i].canget){
                net[2 * i - 1][2 * i] = Edge(1, 0);
                net[2 * i][2 * i - 1] = Edge(0, -1);
            }
            net[2 * k - 1][2 * k].canget = net[2 * k][2 * k - 1].canget = false;
            for (int i = 0; i < m; ++i)
            {
                int a = side[i][0], b = side[i][1];
                net[2 * a][2 * b - 1] = Edge(INF, 0);
                net[2 * b - 1][2 * a] = Edge(0, 0);
                net[2 * b][2 * a - 1] = Edge(INF, 0);
                net[2 * a - 1][2 * b] = Edge(0, 0);
            }
            int sumflow = 0;
            while (BFS())
            {
                sumflow += DFS(2 * c1, INF);
            }
            if (sumflow < netflow)
            {
                netflow = sumflow;
                printf("%d", k);
                if (netflow == 0) break;
                else printf(" ");
            }
            else
            {
                net[2 * k - 1][2 * k].canget = net[2 * k][2 * k - 1].canget = true;
            }
        }
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    log4j配置
    Fragment配合RadioGroup实现点击切换布局
    (转)[原] Android 自定义View 密码框 例子
    标题栏透明度变化
    Android 监听ScrollView的滑动
    Android进度条学习
    Android-正方形的容器
    Android添加图片到ListView或者 RecyclerView显示
    Android打开相机和打开相册
    2020新年快乐
  • 原文地址:https://www.cnblogs.com/albert7xie/p/5323591.html
Copyright © 2020-2023  润新知