SDU程序设计思维Week7-作业 A-TT的魔法猫

程序设计思维Week7-作业

A-TT的魔法猫

Description

有 N 个人以及 M 个胜负关系,每个胜负关系为 A B,表示 A 能胜过 B,且胜负关系具有传递性。即 A 胜过 B,B 胜过 C,则 A 也能胜过 C。
试问有多少对选手的胜负无法预先得知?
输入第一行给出数据组数。
每组数据第一行给出 N 和 M(N , M <= 500)。
接下来 M 行,每行给出 A B,表示 A 可以胜过 B。
对于每一组数据,判断有多少场比赛的胜负不能预先得知。注意 (a, b) 与 (b, a) 等价,即每一个二元组只被计算一次。

Sample

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

Idea

根据题意胜负关系具有传递性,因此可以用Floyd算法求出任意两点的胜负关系(传递闭包),dis[a][b]=1代表a胜b,dis[a][b]=0代表a与b的胜负关系不明。当dis[a][b]=0且dis[b][a]=0即表示a与b的胜负关系无法预测,这就是我们要求目标
首先初始化任意两点之间的距离关系即胜负关系,然后进行Floyd求出任意两点最终的关系,这里为降低复杂度应剪枝,即在第二重循环时判断dis[i][k]是否等于1,是则进行地三重循环,不然不进行,这表明如果i与k的胜负不明确,那么一定无法通过k传递判断i与j的胜负关系。
最后计算胜负关系无法预测的组数,(a,b)与(b,a)等价意味着只需要在矩阵中数对角线的上半部分。

Summary

这题是多源最短路问题的变形,距离关系只有0或1,基本方法是Floyd剪枝求传递闭包,注意最后只数二维数组的一半。
时间复杂度是O(n^3)

Codes

#include <iostream>
using namespace std;
int n,N, M;
bool dis[520][520];

int main()
{
	cin.sync_with_stdio(false);
	cin >> n;
	while (n--) {
		
		cin >> N >> M;

		memset(dis, false, sizeof(dis));
		for (int i = 0; i < M; i++) {
			int a, b;
			cin >> a >> b;
			dis[a][b] = true;

		}
		for (int k = 1; k <= N; k++)
			for (int i = 1; i <= N; i++) {
				if (dis[i][k]) {
					for (int j = 1; j <= N; j++)
					{
						dis[i][j] = (dis[i][j] || (dis[i][k] && dis[k][j]));
						
					}
				}
			}
		int num = 0;
		for (int i = 1; i <= N; i++)
			for (int j = 1; j <= N; j++)
				if (i < j&&(!dis[i][j])&&(!dis[j][i]))num++;
		printf("%d\n", num);
	}
}

发布了21 篇原创文章 · 获赞 5 · 访问量 758

猜你喜欢

转载自blog.csdn.net/weixin_44578615/article/details/105280745