srm 539 T2

题目大意:给定一张图,有T个点,现在有 n 个人要从0号点分别走到 1 ~ n 号点,每个人都是沿着自己最短路径走(有多条最短路径则可任意选一条)。如果在到达终点之前,有个人单独行动,则认为这个人是处在危险中的(只有一个人经过某条边)。问n个人该怎么走使得处在危险中的人数最少。


基本思路:从0号点开始建立一张最短路图,结论:若在最优解中第i个人是安全的,则必然能找到一种方案,使得存在第j个人的路径完全覆盖第i个人的。证明:假设结论不成立,则   存在4条路径 :   0 -> a -> b,  0 -> a -> c,  0 -> d , 0 -> d -> a -> c -> e (中间两人是安全的),但是由于是在最短路图中进行处理的,所以  dis(0 -> a) = dis(0 -> d -> a),所以我们可以进行调整路径:0 - > d -> a - > b , 0 -> a -> c, 0 -> d,  0 -> a -> c -> e,答案不变,但是满足第1条路径覆盖第3条,第4条覆盖第2条,所以结论成立。有了这个结论,原问题就相当于 叫你安排一种方案使得没被覆盖的路径数量最小。这个可以用二分图匹配轻松解决。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 60;
int floyed[N][N], my[N];
bool f[N][N], vis[N];

bool find(int x, int n) {
    for (int i = 1; i <= n; ++i)
	if (f[x][i] && !vis[i]) {
	    vis[i] = true;
	    if (!my[i] || find(my[i], n)) {
		my[i] = x;  
		return true;
	    }
	}
    return false;
}

class SafeReturn {
public:
    int minRisk(int n, vector <string> streets) {
	int T = streets.size();
	memset(floyed, 63, sizeof(floyed));
	memset(f, false, sizeof(f));
	for (int i = 0; i < T; ++i)
	    for (int j = 0; j < T; ++j) 
		if (streets[i][j] != '-') 
		    floyed[i][j] = streets[i][j] - '0';
	for (int i = 0; i < T; ++i)
	    floyed[i][i] = 0;
	for (int k = 0; k < T; ++k)
	    for (int i = 0; i < T; ++i)
		for (int j = 0; j < T; ++j)
		    floyed[i][j] = min(floyed[i][j], floyed[i][k] + floyed[j][k]);
	for (int i = 1; i <= n; ++i)
	    for (int j = 1; j <= n; ++j)
		if (i != j && floyed[0][j] + floyed[j][i] == floyed[0][i]) f[i][j] = true;
	memset(my, 0, sizeof(my));
	int ans = n;
	for (int i = 1; i <= n; ++i) {
	    memset(vis, false, sizeof(vis));
	    if (find(i, n)) -- ans;
	}
	return ans;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值