Floyd解传递闭包

一个小知识点:即用floyd求解两点之间的是否可达

poj1575

题目链接

题意

  • 求出不可能为中位数的水滴

思路:

  • 依据重量关系建图,用floyd求解,求出每个点可到达点的个数和别的点可到达该点的个数,若两个数其中有一个超过\(\frac{n}{2}\),则该点必不可能是中位数点

代码:

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
using namespace std;
const int N = 100;
int g[N][N];
void slove() {
	memset(g, 0 ,sizeof(g));
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= m; ++ i) {
		int u, v;
		cin >> u >> v;
		g[u][v] = 1;
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = 1; i <= n; ++ i) {
			for(int j = 1; j <= n; ++ j) {
				g[i][j] |= g[i][k] & g[k][j];
			}
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; ++ i) {
		int to = 0, from = 0;
		for(int j = 1; j <= n; ++ j) {
			if(i == j) continue;
			to += g[i][j];
			from += g[j][i];
		}
		if(to > n / 2 || from > n / 2) ++ cnt;
	}
	cout << cnt << "\n";
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while(t -- ) {
		slove();
	}
}

poj3660

题目链接

题意

  • 根据胜负关系求出可确定排名的数量

思路:

  • 依据胜负关系建图,用floyd求解,求出每个点可到达点的个数和别的点可到达该点的个数,若两数之和为\(n-1\),则该点可到达其他任意一点,证明该点排名确定

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int N = 105;
int g[N][N];
void slove() {
	int n, m;
	cin >> n >> m;
	for(int i = 0; i < m; ++ i) {
		int x, y;
		cin >> x >> y;
		g[x][y] = 1;
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = 1; i <= n; ++ i) {
			for(int j = 1; j <= n; ++ j) {
				g[i][j] |= g[i][k] & g[k][j];
			}
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; ++ i) {
		int from = 0, to = 0;
		for(int j = 1; j <= n; ++ j) {
			to += g[i][j];
			from += g[j][i];
		}
		if(to + from == n - 1) ++ cnt;
	}
	cout << cnt;
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	slove();
	return 0;
}

cf1383A

题目链接

题意

  • 在A串中选相同字符的位置,改为更大的字符,问最少经过几次修改可变为B串。无法改为B串输出-1

思路:

  • 依照A串与B串修改字符来建图
  • 若A[i] > B[i]则不可能修改为B串,若A[i] < B[i]则在A[i]与B[i]之间建一条单向边
  • 建图完成后,再依照贪心的思想,每次修改都按照字典序来,修改之后查看之后的字符可不可以继承关系
  • 每次修改就将答案加1,最后输出

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;
const int N = 20;
int g[N][N];
void slove() {
	int n;
	cin >> n;
	string s, t;
	cin >> s >> t;
	bool flag = true;
	int cnt = 0;
	memset(g, 0, sizeof(g));
	for(int i = 0; i < n; ++ i) {
		if(s[i] != t[i]) {
			++ cnt;
			if(t[i] < s[i]) {
				flag = false;
				break;
			} else {
				g[s[i] - 'a'][t[i] - 'a'] = 1;
			}
		}
	}
	if(!flag) {
		cout << "-1\n";
		return;
	}
	cnt = 0;
	for(int i = 0; i < N; ++ i) {
		for(int j = 0; j < N; ++ j) {
			if(!g[i][j]) continue;
			++ cnt;
			for(int k = j + 1; k < N; ++ k) {
				g[j][k] |= g[i][k];
			}
			break;
		}
	}
	cout << cnt << "\n";
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t -- ) {
		slove();
	}
	return 0;
}

cf505B

题目链接

题意

  • 统计两点之间有多少条不同颜色的路

思路:

  • 无向边建图,只需注意不同的颜色都要存即可
  • 两点特定颜色可达,需要两点到中间点的该颜色可达

代码一(数组存图):

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int N = 105;
int g[N][N][N];
void slove() {
	memset(g, 0, sizeof(g));
	int n, m, q;
	cin >> n >> m;
	for (int i = 0; i < m; ++ i) {
		int a, b, c;
		cin >> a >> b >> c;
		g[a][b][c] = 1;
		g[b][a][c] = 1;
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = 1; i <= n; ++ i) {
			for(int j = 1; j <= n; ++ j) {
				for(int c = 1; c <= 100; ++ c) {
					g[i][j][c] |= g[i][k][c] && g[k][j][c];
				}
			}
		}
	}
	cin >> q;
	while (q -- ) {
		int u, v;
		cin >> u >> v;
		int cnt = 0;
		for(int i = 1; i <= 100; ++ i) {
			cnt += g[u][v][i];
		}
		cout << cnt << "\n";
	}
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	slove();
	return 0;
}

代码二(bitset存图):

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <bitset>
using namespace std;
const int N = 105;
bitset<101> g[N][N];
void slove() {
	int n, m, q;
	cin >> n >> m;
	for (int i = 1; i <= m; ++ i) {
		int x, y, z;
		cin >> x >> y >> z;
		g[x][y].set(z);
		g[y][x].set(z);
	}
	for (int k = 1; k <= n; ++ k) {
		for (int i = 1; i <= n; ++ i) {
			for (int j = 1; j <= n; ++ j) {
				g[i][j] |= g[i][k] & g[k][j];
			}
		}
	}
	cin >> q;
	while (q -- ) {
		int u, v;
		cin >> u >> v;
		cout << g[u][v].count() << "\n";
	}
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	slove();
	return 0;
}

hdu1704

题目链接

题意

  • 根据胜负关系判断有多少对不能确定胜负关系的

思路:

  • 裸的模板题
  • 这题必须得用bitset优化,不然TLE

代码一:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <bitset>
#include <vector>
using namespace std;
const int N = 505;
bitset<N> g[N];
int n, m;
void init() {
	for(int i = 0; i < N; ++ i) g[i].reset();
	for(int i = 0; i < N; ++ i) g[i].set(i);
	return;
}
void slove() {
	init();
	cin >> n >> m;
	for(int i = 1; i <= m; ++ i) {
		int u, v;
		cin >> u >> v;
		g[u].set(v);
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = 1; i <= n; ++ i) {
			bitset<N> tmp;
			if(g[i].test(k)) tmp.set();
			else tmp.reset();
			g[i] |= tmp & g[k];
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; ++ i){
		for(int j = i + 1; j <= n; ++ j){
			if(!g[i].test(j) && !g[j].test(i)) ++ cnt;
		}
	}
	cout << cnt << "\n";
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t -- ) {
		slove();
	}
	return 0;
}

代码二(bitset更新时更简单的写法):

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <bitset>
#include <vector>
using namespace std;
const int N = 505;
bitset<N> g[N];
int n, m;
void init() {
	for(int i = 0; i < N; ++ i) g[i].reset();
	for(int i = 0; i < N; ++ i) g[i].set(i);
	return;
}
void slove() {
	cin >> n >> m;
	init();
	for(int i = 1; i <= m; ++ i) {
		int u, v;
		cin >> u >> v;
		g[u].set(v);
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = 1; i <= n; ++ i) {
			if(g[i][k]) g[i] |= g[k];
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; ++ i){
		for(int j = i + 1; j <= n; ++ j){
			if(g[i].test(j) == 0 && g[j].test(i) == 0) ++ cnt;
		}
	}
	cout << cnt << "\n";
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t -- ) {
		slove();
	}
	return 0;
}
posted @ 2023-02-01 15:21  lemonsbiscuit  阅读(24)  评论(0编辑  收藏  举报