PAT(T) - 1001. Battle Over Cities - Hard Version (35)

1001. Battle Over Cities - Hard Version (35)

时间限制
800 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

It is vitally important to have all the cities connected by highways in a war. If a city is conquered by the enemy, all the highways from/toward that city will be closed. To keep the rest of the cities connected, we must repair some highways with the minimum cost. On the other hand, if losing a city will cost us too much to rebuild the connection, we must pay more attention to that city.

Given the map of cities which have all the destroyed and remaining highways marked, you are supposed to point out the city to which we must pay the most attention.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N (<=500), and M, which are the total number of cities, and the number of highways, respectively. Then M lines follow, each describes a highway by 4 integers:

City1 City2 Cost Status

where City1 and City2 are the numbers of the cities the highway connects (the cities are numbered from 1 to N), Cost is the effort taken to repair that highway if necessary, and Status is either 0, meaning that highway is destroyed, or 1, meaning that highway is in use.

Note: It is guaranteed that the whole country was connected before the war.

Output Specification:

For each test case, just print in a line the city we must protest the most, that is, it will take us the maximum effort to rebuild the connection if that city is conquered by the enemy.

In case there is more than one city to be printed, output them in increasing order of the city numbers, separated by one space, but no extra space at the end of the line. In case there is no need to repair any highway at all, simply output 0.

Sample Input 1:
4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 1 0
Sample Output 1:
1 2
Sample Input 2:
4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 2 1
Sample Output 2:
0

题目读了好几遍,终于看懂了。题意是给你一个图,图里有N个点M条边。每攻占一个点,与这个点相连的所有边都没了,为了让其余的点连通需要花费一定的代价,然后让你计算哪些节点是至关重要的?至关重要的意思是说如果我们失去了节点x,为了让其他点连通(除了x)花费的代价是最大的。简单的说,就是去每次计算假如失去节点i,求剩余节点的MST,然后我们得到N个MST权值,其中最大的权值对应的节点编号就是答案。

样例解释:样例1失去1号和2号节点的MST权值是1,而其余节点的MST权值是0,所以答案就是1和2

样例2不管失去哪个节点,其余节点都能连通,所以答案是0。

题目有个坑是可能剩余节点无法连通,这说明丢掉的那个城市是最关键的。。因为连通性都不能保证了,MST权值可以定义为很大很大的一个数,程序里用INF表示。

我刚开始的思路建了两个图(因为每次要修改一些边),每进行一趟MST计算都初始化图,这么做的结果是超时了,来回交换太耗时间。后来看了别人的程序,发现完全没必要建图,其中程序里有一个核心的地方是Node node( a, b, s ? 0 : c ); 这样就解决建图的问题了。。

#include <cstdio>
#include <algorithm>
#include <vector>

#define MAX 500 + 10
#define INF 0x3fffffff

using namespace std;

typedef struct node {
    node( int xx, int yy, int v ) {
        x = xx;
        y = yy;
        val = v;
    }
    int x;
    int y;
    int val;
} Node;

int n, m;
int father[MAX];
vector<Node> vec;
vector<int> ans;
int Max = 0;

void initSet() {
    for( int i = 1; i <= n; i++ ) father[i] = i;
}

int findFather( int x ) {
    int a = x;
    while( x != father[x] ) x = father[x];
    while( a != father[a] ) {
        int z = a;
        a = father[a];
        father[z] = x;
    }
    return x;
}

void Kruskal( int x ) {
    int sum = 0;
    int cnt = 0;
    for( int i = 0; i < vec.size(); i++ ) {
        int a = vec[i].x;
        int b = vec[i].y;
        if( a == x || b == x ) continue;
        int faA = findFather( a );
        int faB = findFather( b );
        if( faA != faB ) {
            father[faA] = faB;
            cnt++;
            sum = sum + vec[i].val;
        }
    }
    //printf( "%d %d\n", cnt, sum );

    if( cnt != n - 2 ) sum = INF;
    if( sum > Max ) {
        Max = sum;
        ans.clear();
        ans.push_back( x );
    }
    else if( sum == Max && sum != 0 ) ans.push_back( x );
}

int cmp( Node a, Node b ) {
    return a.val < b.val;
}

int main() {
    scanf( "%d%d", &n, &m );
    int a, b, c, s;
    for( int i = 0; i < m; i++ ) {
        scanf( "%d%d%d%d", &a, &b, &c, &s );
        Node node( a, b, s ? 0 : c );
        vec.push_back( node );
    }

    sort( vec.begin(), vec.end(), cmp );
    for( int i = 1; i <= n; i++ ) {
        initSet();
        Kruskal( i );
    }

    if( ans.empty() ) printf( "0\n" );
    else {
        for( int i = 0; i < ans.size(); i++ ) {
            if( i == 0 ) printf( "%d", ans[i] );
            else printf( " %d", ans[i] );
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值