@LinKArftc
2015-08-14T11:51:06.000000Z
字数 6847
阅读 1133
数据结构
并查集
经典的食物链
这题有个大坑,就是不能多组数据读入,调了一上午,最终看discuss才发现这个坑,快哭了都ToT
需要记录子节点与父节点的关系 rela[i], 0表示同类,1 吃,2 被吃,然后就是递推了
/*
ID: LinKArftc
PROG: 1182.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50010;
int n, k;
int rela[maxn];//0 same, 2 eat, 3 eaten;
int father[maxn];
void init() {
for (int i = 1; i <= n; i ++) {
father[i] = i;
rela[i] = 0;
}
}
int find(int a) {
if (father[a] == a) return a;
int fa = father[a];
father[a] = find(father[a]);
rela[a] = (rela[a] + rela[fa] + 3) % 3;
return father[a];
}
void unin(int op, int a, int b) {
int x = find(a);
int y = find(b);
father[y] = x;
rela[y] = (3 + rela[a] - rela[b] - op) % 3;
}
int main() {
scanf("%d %d", &n, &k);
int ans = 0;
int op, a, b;
init();
for (int i = 1; i <= k; i ++) {
scanf("%d %d %d", &op, &a, &b);
if (a > n || b > n) ans ++;
else if (a == b && op == 2) ans ++;
else {
int x = find(a);
int y = find(b);
if (x == y) { // relation sure
if (op == 1 && rela[a] != rela[b]) ans ++;
if (op == 2 && (rela[a] - rela[b] + 3) % 3 != 1) ans ++;
} else unin(op - 1, a, b);
}
}
printf("%d\n", ans);
return 0;
}
跟上一题差不多
/*
ID: LinKArftc
PROG: 1703.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int father[maxn];
int rela[maxn];//1 same, 0 dif;
int n, m;
void init() {
for (int i = 1; i <= n; i ++) {
father[i] = i;
rela[i] = 1;
}
}
int find(int a) {
int x = father[a];
if (x != a) {
father[a] = find(x);
if (rela[a] == rela[x]) rela[a] = 1;
else rela[a] = 0;
}
return father[a];
}
void unin(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
father[x] = y;
if (rela[a] == rela[b]) rela[x] = 0;
else rela[x] = 1;
}
}
int main() {
// freopen("input.txt", "r", stdin);
int T;
int a, b;
char op;
scanf("%d", &T);
while (T --) {
scanf("%d %d", &n, &m);
init();
for (int i = 1; i <= m; i ++) {
scanf(" %c %d %d", &op, &a, &b);
if (op == 'A') {
int x = find(a);
int y = find(b);
if (x != y) {
printf("Not sure yet.\n");
continue;
}
if (rela[a] == rela[b]) {
printf("In the same gang.\n");
continue;
} else {
printf("In different gangs.\n");
continue;
}
} else {
unin(a, b);
}
}
}
return 0;
}
题意:
当前节点所在集合放到目标节点所在集合上,询问当前节点下面有多少节点思路:
cnt[i] 记录该集合是第几个加入该集合的
sum[i] 该集合中元素个数
注意 cnt[i] 初始化为 0, 方便后面路径压缩时关系递推
/*
ID: LinKArftc
PROG: 1988.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30010;
int father[maxn];
int cnt[maxn]; // 第几个加入该集合
int sum[maxn]; // 该集合中元素个数
void init() {
for (int i = 0; i < maxn; i ++) {
father[i] = i;
sum[i] = 1;
cnt[i] = 0; //从 0 开始方便 line41 计算
}
}
int find(int a) {
if (a != father[a]) {
int fa = father[a];
father[a] = find(fa);
cnt[a] += cnt[fa];
}
return father[a];
}
void unin(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
father[y] = x;
cnt[y] += sum[x];
sum[x] += sum[y];
}
}
int main() {
// freopen("input.txt", "r", stdin);
init();
int n, p;
char op;
int a, b;
scanf("%d", &p);
while (p --) {
scanf(" %c", &op);
if (op == 'M') {
scanf("%d %d", &a, &b);
unin(a, b);
} else {
scanf("%d", &a);
int x = find(a);
printf("%d\n", sum[x] - cnt[a] - 1);
}
}
return 0;
}
这题有个大坑,0 0 也就是空树也是树。。哔了狗了。。。
/*
ID: LinKArftc
PROG: 1308.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int father[maxn];
int vis[maxn];
void init() {
for (int i = 1; i < maxn; i ++) father[i] = i;
memset(vis, 0, sizeof(vis));
}
int find(int a) {
if (a != father[a]) father[a] = find(father[a]);
return father[a];
}
void unin(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) father[y] = x;
}
int main() {
// freopen("input.txt", "r", stdin);
int caseNo = 1;
int a, b;
init();
bool flag = false;
while (~scanf("%d %d", &a, &b)) {
if (a == -1 && b == -1) break;
if (a == 0 && b == 0) {
if (flag == false) {
int cnt = 0;
for (int i = 1; i < maxn; i ++) {
if (vis[i] && (i == father[i])) cnt ++;
}
if (cnt <= 1) printf("Case %d is a tree.\n", caseNo ++);
else printf("Case %d is not a tree.\n", caseNo ++);
}
init();
flag = false;
continue;
}
if (flag) continue;
vis[a] = 1;
vis[b] = 1;
int x = find(a);
int y = find(b);
if (a == b || (a != b && x == y)) {
printf("Case %d is not a tree.\n", caseNo ++);
flag = true;
} else {
unin(a, b);
}
}
return 0;
}
并查集的最简单模型了
/*
ID: LinKArftc
PROG: 2524.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int father[50005];
int find(int x) {
if (x != father[x]) father[x] = find(father[x]);
return father[x];
}
int main() {
int n, m;
int i, j;
int num;
int a, b;
j = 1;
while (cin >> n >> m && (n || m)) {
num = n;
for (i = 0; i < n; i ++) father[i] = i;
for (i = 0; i < m; i++) {
cin >> a >> b;
int x = find(a);
int y = find(b);
if (x != y) {
father[y] = x;
num --;
}
}
printf("Case %d: %d\n", j, num);
j ++;
}
return 0;
}
相对于食物链的三性 两性问题比较简单
/*
ID: LinKArftc
PROG: 2492.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2010;
int n, q;
int father[maxn];
int rela [maxn]; // 0 same, 1 dif
void init() {
for (int i = 1; i <= n; i ++) father[i] = i;
memset(rela, 0, sizeof(rela));
}
int find(int a) {
if (a != father[a]) {
int fa = father[a];
father[a] = find(father[a]);
rela[a] = (rela[a] + rela[fa]) % 2;
}
return father[a];
}
void unin(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
father[x] = y;
rela[x] = (rela[a] + rela[b] + 1) % 2;
}
}
int main() {
// freopen("input.txt", "r", stdin);
int T, caseNo = 1;
int a, b;
scanf("%d", &T);
while (T --) {
printf("Scenario #%d:\n", caseNo ++);
scanf("%d %d", &n, &q);
init();
bool flag = false;
for (int i = 1; i <= q; i ++) {
scanf("%d %d", &a, &b);
if (flag) continue;
int x = find(a);
int y = find(b);
if (x == y) {
if (rela[a] == rela[b]) {
flag = true;
printf("Suspicious bugs found!\n\n");
continue;
}
}
else unin(a, b);
}
if (flag == false) printf("No suspicious bugs found!\n\n");
}
return 0;
}
很久之前写的了
/*************************************************************************
> File Name: 2236.cpp
> Author: LinKArftc
> Created Time: 2015/6/4 LinK 01:32:24
*************************************************************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXN 1010
int n, rank[MAXN], pa[MAXN], rep[MAXN];
struct Node {
int x, y;
} pos[MAXN];
void init() {
for (int i = 1; i <= n; i ++) {
rank[i] = 0;
pa[i] = i;
}
}
int find(int x) {
if (x != pa[x]) pa[x] = find(pa[x]);
return pa[x];
}
void uion(int x, int y) {
x = find(pa[x]);
y = find(pa[y]);
if (x != y) {
if (rank[x] < rank[y]) pa[x] = y;
else {
pa[y] = x;
if (rank[x] == rank[y]) rank[x] ++;
}
}
}
double dis(int a, int b) {
Node x, y;
x = pos[a];
y = pos[b];
return sqrt(1.0*(x.x-y.x)*(x.x-y.x) + 1.0*(x.y-y.y)*(x.y-y.y));
}
int main() {
// freopen("input.txt", "r", stdin);
char c;
int x, y, cnt;
double d;
scanf("%d%lf", &n, &d);
for (int i = 1; i <= n; i ++) scanf("%d %d", &pos[i].x, &pos[i].y);
cnt = 0;
init();
while (~scanf(" %c %d", &c, &x)) {
if (c == 'O') {
for (int i = 0; i < cnt; i ++) {
if (dis(rep[i], x) <= d) uion(rep[i], x);
}
rep[cnt ++] = x;
} else {
scanf("%d", &y);
if (find(x) == find(y)) printf("SUCCESS\n");
else printf("FAIL\n");
}
}
return 0;
}
简单,很久之前写的代码,稍微改下代码风格
/*
ID: LinKArftc
PROG: 1611.cpp
LANG: C++
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30010;
int father[maxn];
int tmp[maxn];
int find(int x) {
if (x != father[x]) father[x] = find(father[x]);
return father[x];
}
void unin(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) father[x] = y;
}
int main() {
// freopen("input.txt", "r", stdin);
int n, k;
while (~scanf("%d %d", &n, &k)) {
if (n == 0 && k == 0) break;
for (int i = 0; i < n; i ++) father[i] = i;
for (int i = 1; i <= k; i ++) {
int m, t1, t2;
scanf("%d %d", &m, &t1);
for (int j = 2; j <= m; j ++) {
scanf("%d", &t2);
unin(t1, t2);
}
}
int ans = 1;
for (int i = 1; i < n; i ++) {
if (find(i) == find(0)) ans ++;
}
printf("%d\n", ans);
}
return 0;
}