【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\n", 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("\n");
    return 0;
}
时间: 2024-10-06 04:42:34

【USACO 5.4.3】TeleCowmunication的相关文章

【USACO 1.3.4】牛式

[題目描述 ] 下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式. * * * x * * ---------- * * * * * * ---------- * * * * 数字只能取代*,当然第一位不能为0,况且给定的数字里不包括0. 注意一下在美国的学校中教的"部分乘积",第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积. 写一个程序找出所有的牛式. [格式] INPUT FORMAT: (f

【USACO 1.2.2】方块转换

[问题描述] 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针转90度. 2:转180度:图案按顺时针转180度. 3:转270度:图案按顺时针转270度. 4:反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像). 5:组合:图案在水平方向翻转,然后再按照1到3之间的一种再次转换. 6:不改变:原图案不改变. 7:无效转换:无法用以上方法得到新图案. 如

【USACO 2.3.4】货币系统

[描述] 母牛们不但创建了它们自己的政府而且选择了建立了自己的货币系统.由于它们特殊的思考方式,它们对货币的数值感到好奇. 传统地,一个货币系统是由1,5,10,20 或 25,50, 和 100的单位面值组成的. 母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值. 举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它. 写一个程序来计算有多少种方法用给定的货币系统来构

【USACO 2.3.3】零数列

[题目描述] 请考虑一个由1到N(N=3, 4, 5 ... 9)的数字组成的递增数列:1 2 3 ... N. 现在请在数列中插入“+”表示加,或者“-”表示减,“ ”表示空白(例如1-2 3就等于1-23),来将每一对数字组合在一起(请不要在第一个数字前插入符号). 计算该表达式的结果并判断其值是否为0. 请你写一个程序找出所有产生和为零的长度为N的数列. [格式] PROGRAM NAME: zerosum INPUT FORMAT 单独的一行表示整数N (3 <= N <= 9). O

【USACO 2.3.5】控制公司

[题目描述] 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分.例如,福特公司拥有马自达公司12%的股票.据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了: 公司A = 公司B. 公司A拥有大于50%的公司B的股票. 公司A控制K(K >= 1)个公司,记为C1, ..., CK,每个公司Ci拥有xi%的公司B的股票,并且x1+ .... + xK > 50%. 给你一个表,每行包括三个数(i,j,p):表明公司i享有公司j的p%的股票.计算所有的数对(h

【USACO 1.4.2】时钟

[题目描述] 考虑将如此安排在一个 3 x 3 行列中的九个时钟: |-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |---

【USACO 1.4.1】铺放矩形块

[描述] 给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠.所谓最小矩形指该矩形面积最小. 所有4个矩形块的边都与封闭矩形的边相平行,图1示出了铺放4个矩形块的6种方案.这6种方案是仅可能的基本铺放方案.因为其它方案能由基本方案通过旋转和镜像反射得到. 可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长. (分类注解:这里的分类依据可以视为是不同的面积计算公式.) [格式] INPUT FORMAT: (file packrec.in)

【USACO 1.2.1】挤牛奶

[问题描述] 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300时刻(从5点开始计时,秒为单位)给他的牛挤奶,一直到1000时刻.第二个农民在700时刻开始,在 1200时刻结束.第三个农民在1500时刻开始2100时刻结束.期间最长的至少有一个农民在挤奶的连续时间为900秒(从300时刻到1200时刻),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300时刻(从1200时刻到1500时刻). 你的任务是编一个程序,读入一个有N个农民(1 <= N <= 5000

【USACO 3.1.5】联系

[描述] 奶牛们开始对用射电望远镜扫描牧场外的宇宙感兴趣.最近,他们注意到了一种非常奇怪的脉冲调制微波从星系的中央发射出来.他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星发出的. 帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相.他们在寻找长度在A到B之间(含)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12).他们在找那些重复得最多的比特序列.一个输入限制告诉你应输出多少频率最多的序列. 符合的序列可能会重叠,并且至少出