1001. Battle Over Cities - Hard Version (35)解题报告

思路

用读入的高速公路的数据对城市做并查集。对被毁坏的公路按费用从小到大排序。

去掉某一个城市,先利用正在使用的公路,对各个城市进行合并。然后利用被摧毁的公路,对城市进行合并,并把所需的修复费用进行加和。

通过画面

 

代码

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

struct road {
	int city1, city2, weight, status;
};

const int MAX = 10000000;
const int M = 500 * 499;
int cmp(const void *r1, const void *r2);
int findroot(int cityset[], int index);
int unionset(int cityset[], int index1, int index2);

int main(void) {
	int n, m, i, j, usecnt = 0, destcnt = 0;
	road tmp;
	road *use, *destroyed;
	use = new road[M];
	destroyed = new road[M];
    // 加快输入
	setvbuf(stdin, new char[1 << 20], _IOFBF, 1 << 20);
	setvbuf(stdout, new char[1 << 20], _IOFBF, 1 << 20);
	scanf("%d %d", &n, &m);
	for (i = 0; i < m; i++) {
		scanf("%d %d %d %d", &tmp.city1, &tmp.city2, &tmp.weight, &tmp.status);
		if (tmp.status) {
			use[usecnt++] = tmp;
		}
		else {
			destroyed[destcnt++] = tmp;
		}
	}
	qsort(destroyed, destcnt, sizeof(road), cmp); // 将被摧毁的道路按照修复费用从小到大排序
	int *cityset = new int[n + 1];
	set<int> pro;
	int max_cost = 0, cnt, cost;
	for (i = 1; i < n + 1; i++) { // 遍历所有的城市,假定该城市已被敌人占领
		for (j = 0; j < n + 1; j++) {
			cityset[j] = -1;
		}
		cnt = cost = 0; // cnt的绝对值表示最大的连通图结点个数,cost表示最小的修复费用
		for (j = 0; j < usecnt && cnt != -n + 1; j++) {  // 遍历所有正常道路,寻找最大的连通图
			if (use[j].city1 == i || use[j].city2 == i) {
				continue; // 如果道路两端的某城市已被占领,则跳过
			}
			int index = unionset(cityset, use[j].city1, use[j].city2);
			if (index > 0 && cityset[index] < cnt) {
				cnt = cityset[index];
			}
		}
		for (j = 0; j < destcnt && cnt != -n + 1; j++) { // 遍历已被摧毁的道路
			if (destroyed[j].city1 == i || destroyed[j].city2 == i) {
				continue; // 道路两端有城市被占领,则放弃修复
			}
			int index = unionset(cityset, destroyed[j].city1, destroyed[j].city2);
			if (index > 0) { // 如果道路两端的城市属于不同的连通图
				cnt = cityset[index] < cnt ? cityset[index] : cnt;
				cost += destroyed[j].weight;
			}
		}
		if (cnt == -n + 1 && cost && cost == max_cost) { // 如果联通了n-1个城市,且修复费用和目前大值齐平
			pro.insert(i);
		}
		else if (cnt == -n + 1 && cost && cost > max_cost) { // 如果费用高于目前最大值
			pro.clear();
			pro.insert(i);
			max_cost = cost;
		}
		else if (cnt > -n + 1 && max_cost == MAX) { // 如果不能联通所有未被占领城市,且pro集合中没有代价更小的城市
			pro.insert(i);
		}
		else if (cnt > -n + 1 && max_cost != MAX) { // 如果不能联通所有未被占领城市,且pro集合中有代价更小的城市
			pro.clear();
			pro.insert(i);
			max_cost = MAX;
		}
	}
	if (pro.size()) { // 输出结果
		set<int>::iterator it = pro.begin();
		printf("%d", *it++);
		for (; it != pro.end(); it++) {
			printf(" %d", *it);
		}
	}
	else {
		puts("0");
	}
	delete[] cityset;
	delete[] use;
	delete[] destroyed;
	return 0;
}

int cmp(const void *v1, const void *v2) {
	road *r1, *r2;
	r1 = (road *)v1;
	r2 = (road *)v2;
	return r1->weight - r2->weight;
}
int findroot(int cityset[], int index) { // 寻找根的过程中,把所有的结点直接连接到根上
	if (cityset[index] < 0) {
		return index;
	}
	else {
		return cityset[index] = findroot(cityset, cityset[index]);
	}
}
int unionset(int cityset[], int index1, int index2) {
	int root1, root2;
	root1 = findroot(cityset, index1);
	root2 = findroot(cityset, index2);
	if (root1 == root2) {
		return -1;
	}
	else { // cityset[root]的值是连通图结点数的相反数
		if (cityset[root1] > cityset[root2]) {
			cityset[root2] += cityset[root1];
			cityset[root1] = root2;
			return root2;
		}
		else {
			cityset[root1] += cityset[root2];
			cityset[root2] = root1;
			return root1;
		}
	}
}

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值