训练链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=173#overview
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 25461 | Accepted: 12576 |
Description
Input
Output
Sample Input
10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
10 4
2 3
4 5
4 8
5 8
0 0
Sample Output
Case 1: 1
Case 2: 7
Hint
Source
#include
int fa[50005];
void UF_set(int n)
{
for(int i = 1; i <= n; i++)
fa[i] = i;
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
fa[r1] = r2;
}
int main()
{
int n, m, ans, ca = 1;
while(scanf("%d %d", &n, &m) != EOF && (m + n))
{
ans = 0;
UF_set(n);
int a, b;
for(int i = 0; i < m; i++)
{
scanf("%d %d", &a, &b);
Union(a, b);
}
for(int i = 1; i <= n; i++)
if(i == Find(i))
ans++;
printf("Case %d: %d\n", ca++, ans);
}
}
Time Limit: 1000MS | Memory Limit: 20000K | |
Total Submissions: 23748 | Accepted: 11584 |
Description
Input
Output
Sample Input
100 4 2 1 2 5 10 13 11 12 14 2 0 1 2 99 2 200 2 1 5 5 1 2 3 4 5 1 0 0 0
Sample Output
4 1 1
Source
#include
int const MAX = 30000 + 5;
int fa[MAX];
void UF_set(int n)
{
for(int i = 0; i < n; i++)
fa[i] = i;
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 == 0)
fa[r2] = r1;
else if(r2 == 0)
fa[r1] = r2;
else
fa[r1] = r2;
}
int main()
{
int n, m, ans;
while(scanf("%d %d", &n, &m) != EOF && (n + m))
{
ans = 0;
UF_set(n);
for(int i = 0; i < m; i++)
{
int get, fir, k;
scanf("%d %d", &k, &fir);
for(int j = 1; j < k; j++)
{
scanf("%d", &get);
Union(get, fir);
}
}
for(int i = 0; i < n; i++)
if(Find(i) == 0)
ans++;
printf("%d\n", ans);
}
}
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 32909 | Accepted: 10158 |
Description
Input
Output
Sample Input
1 5 5 A 1 2 D 1 2 A 1 2 D 2 4 A 1 4
Sample Output
Not sure yet. In different gangs. In the same gang.
Source
继续假设,x的当前集合根节点rx,y的当前集合根节点ry。如果rx和ry不相同,那么我们把ry合并到rx上,并且更新w[ry]值(注意:w[i]表示i当前集合根节点到i的偏移量)
此时 rx->ry = rx->x + x->y + y->ry,(向量运算)
上式进一步转化为:rx->ry = (w[x]+1-w[y])%2 = w[ry],(模2保证偏移量取值始终在[0,1])
接下来把这个想法再运用到路径压缩中:
rrx
| \
rx \
| /
| /
x
路径压缩过程中会将rx的父亲变为x的父亲,所以要改变相对关系,即偏移量。
rrx->rx+rx->x=rrx->x;
转换成:w[x]=(w[rx]+w[x])%2;
#include
int const MAX = 1e5 + 5;
int fa[MAX], w[MAX], n;
void UF_set()
{
for(int i = 1 ; i <= n; i++)
{
fa[i] = i;
w[i] = 0;
}
}
int Find(int x)
{
if(x == fa[x])
return x;
int tmp = fa[x];
fa[x] = Find(fa[x]);
w[x] = (w[x] + w[tmp]) % 2;
return fa[x];
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
{
fa[r2] = r1;
w[r2] = (w[a] + 1 - w[b]) % 2;
}
}
int main()
{
int T, m;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &m);
UF_set();
for(int i = 0; i < m; i++)
{
char ch[2];
int x, y;
scanf("%s %d %d", ch, &x, &y);
if(ch[0] == 'D')
Union(x, y);
if(ch[0] == 'A')
{
if(Find(x) == Find(y))
{
if(w[x] == w[y])
printf("In the same gang.\n");
else
printf("In different gangs.\n");
}
else
printf("Not sure yet.\n");
}
}
}
}
Time Limit: 10000MS | Memory Limit: 65536K | |
Total Submissions: 29242 | Accepted: 9538 |
Description
Input
Output
Sample Input
2 3 3 1 2 2 3 1 3 4 2 1 2 3 4
Sample Output
Scenario #1: Suspicious bugs found! Scenario #2: No suspicious bugs found!
Hint
Source
#include
int const MAX = 2005;
int fa[MAX], w[MAX];
int n;
bool flag;
void UF_set()
{
for(int i = 1; i <= n; i++)
{
fa[i] = i;
w[i] = 0;
}
flag = false;
}
int Find(int x)
{
if(x == fa[x])
return x;
int tmp = fa[x];
fa[x] = Find(fa[x]);
w[x] = (w[x] + w[tmp]) % 2;
return fa[x];
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 == r2 && w[a] == w[b])
flag = true;
else
{
fa[r2] = r1;
w[r2] = (w[a] + 1 - w[b]) % 2;
}
}
int main()
{
int T, m;
scanf("%d", &T);
for(int ca = 1; ca <= T; ca++)
{
scanf("%d %d", &n, &m);
UF_set();
for(int i = 0; i < m; i++)
{
int x, y;
scanf("%d %d", &x, &y);
if(!flag)
Union(x, y);
}
if(flag)
printf("Scenario #%d:\nSuspicious bugs found!\n", ca);
else
printf("Scenario #%d:\nNo suspicious bugs found!\n", ca);
if(ca != T)
printf("\n");
}
}
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 22910 | Accepted: 7860 |
Description
Input
Output
Sample Input
6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1
Sample Output
Case 1 is a tree. Case 2 is a tree. Case 3 is not a tree.
Source
#include
int const MAX = 1e4 + 5;
int fa[MAX];
bool vis[MAX], flag;
int n, e; //点数和边数
void init()
{
flag = true;
n = 0, e = 0;
for(int i = 0; i < MAX; i++)
{
fa[i] = i;
vis[i] = false;
}
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
fa[r2] = r1; //不能反!
else //若根相同,又a与b相连必然成环不是树
flag = false;
}
int main()
{
int a, b, ca = 1;
while(scanf("%d %d", &a ,&b) && (a + b) != -2)
{
if(a == 0 && b == 0)
{
printf("Case %d is a tree.\n", ca++);
continue;
}
init();
while(a + b)
{
Union(a, b);
if(!vis[a])
{
vis[a] = true;
n++;
}
if(!vis[b])
{
vis[b] = true;
n++;
}
e++;
scanf("%d %d", &a, &b);
}
if(n != e + 1)
flag = false;
if(flag)
printf("Case %d is a tree.\n", ca++);
else
printf("Case %d is not a tree.\n", ca++);
}
}