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;
}