Problem A:
原题链接:http://poj.org/problem?id=2236
题目大意:
输入N和d。表示有N台电脑,两个电脑可以直接连接的最大距离为d(这个只输入一次!!!)。电脑的编号为1~N。然后有多次询问。O X表示修复编号为X的电脑。S A B表示询问A和B是否连通(如果A和B连通,B和C连通。那么A和C也连通 )。如果连通输出“SUCCESS”。否则输出“FAIL”
思路:
因为之前输入N台电脑时输入的是坐标。所以用结构体可以很好的解决这个问题。
其余的就和一般的并查集没有什么区别了。按照模板写就可以了
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int N,d;
int root[1005];
int open[1005];
struct Point
{
int x;
int y;
}node[1005];
int find ( int x )
{
return x == root[x] ? x : find( root[x] );
}
void connect( int x )
{
int i;
for( i = 1; i <= N; i++ )
if( open[i] && i != x )
{
int root1,root2;
root1 = find( x );
root2 = find( i );
if( root1 != root2 )
if( (node[x].x - node[i].x)*(node[x].x - node[i].x) + (node[x].y - node[i].y )*(node[x].y - node[i].y ) <= d*d )
root[root2] = root1;
}
}
int main()
{
memset( open,0,sizeof(open ));
scanf("%d %d",&N,&d);
int i;
for( i = 1; i <= N; i++ )
{
scanf("%d %d",&node[i].x ,&node[i].y );
root[i] = i;
}
char order;
int x,y;
while(~scanf("\n%c",&order) )
{
if( order == 'O' )
{
scanf("%d",&x);
open[x] = 1;
connect( x );
}
else
{
scanf("%d %d",&x,&y);
x = find( x );
y = find( y );
if( x == y )
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
return 0;
}
Problem B:
原题链接:http://poj.org/problem?id=1611
题目大意:
输入n和m。表示有n个学生(没什么卵用)分成m组。学生的编号是从0~n-1。0号学生每个样例都是默认被标记的。接下来有m行。每行第一个整数K表示的是这个分组有多少个学生。接着输入K个数。如果一个分组中有一人被标记。那么整组的人都被标记。问有多少人被标记
思路:
这道题我自己的思路写成的代码是WA了的
所以这里就不说了。
直接贴套模板代码
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int root[30005];
int rank[30005];//模板上说这是按秩赋值。好像是一种优化。
int num[30005];
void make_set( int x )
{
root[x] = x;
rank[x] = 0;
num[x] = 1;
}
int find_set( int x )
{
int r,tmp;
r = x;
while( root[r] != r )
{
r = root[r];
}
while( x != r )
{
tmp = root[x];
root[x] = r;
x = tmp;
}
return x;
}
void union_set( int x, int y )
{
x = find_set( x );
y = find_set( y );
if( x == y )
return;
if( rank[x] > rank[y] )
{
root[y] = x;
num[x] += num[y];
}
else
{
root[x] = y;
if( rank[y] == rank[x] )
rank[y]++;
num[y] += num[x];
}
}
int main()
{
while( ~scanf("%d %d",&n,&m) )
{
int i,number,x,y,j;
if( n == 0 && m == 0 )
break;
for( i = 0; i < n; i++ )
make_set( i );
for( i = 0; i < m; i++ )
{
scanf("%d",&number);
scanf("%d",&x);
for( j = 1; j < number; j++ )
{
scanf("%d",&y);
union_set( x, y);
x = y;
}
}
int sum;
sum = find_set( 0 );
printf("%d\n",num[sum]);
}
return 0;
}
Problem C
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1213
题目大意:
输入一个T(1 <= T <= 25 )。一共有T个测试样例。接着就是M和N。一共M人,N个条信息。简单的说就是。认识的人坐一起。A认识B。B认识C。那么A认识C。问要多少桌子
思路:
看起来就很简单的样子。其实就是那么简单。直接看代码
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int T;
int root[30005];
void make_set( int x )
{
root[x] = x;
}
int find_set( int x )
{
return x == root[x] ? x : find_set( root[x] );
}
void union_set( int x, int y )
{
x = find_set( x );
y = find_set( y );
if( x != y )
root[y] = x;
}
int main()
{
scanf("%d",&T);
while( T-- )
{
scanf("%d %d",&n,&m);
int i,x,y;
for( i = 1; i<= n; i++ )
make_set( i );
for( i = 1; i <= m ; i++ )
{
scanf("%d %d",&x,&y);
union_set( x,y );
}
int sum;
sum = 0;
for( i = 1; i <= n; i++ )
{
if( root[i] == i )
sum++;
}
printf("%d\n",sum);
}
return 0;
}
Problem D
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232
题目大意:
(中文题。略过)
思路:
只要把C的代码改一改就可以A了。直接上代码
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int root[30005];
void make_set( int x )
{
root[x] = x;
}
int find_set( int x )
{
return x == root[x] ? x : find_set( root[x] );
}
void union_set( int x, int y )
{
x = find_set( x );
y = find_set( y );
if( x != y )
root[y] = x;
}
int main()
{
while( ~scanf("%d",&n) )
{
if( n == 0 ) break;
scanf("%d",&m);
int i,x,y;
for( i = 1; i<= n; i++ )
make_set( i );
for( i = 1; i <= m ; i++ )
{
scanf("%d %d",&x,&y);
union_set( x,y );
}
int sum;
sum = 0;
for( i = 1; i <= n; i++ )
{
if( root[i] == i )
sum++;
}
printf("%d\n",sum-1);
}
return 0;
}
Problem E
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1272
题目大意:
(中文题,略过)
思路:
(没有思路QAQ)
介绍二狗的奇门秘术:
判断点的个数和边的条数。如果V(点) - 1 = V(边 )
输出yes,否则输出no
(虽然后来被无情打脸了)
网络大神代码如下:
(大神博客链接:http://www.cnblogs.com/liaoguifa/archive/2012/12/21/2828670.html)
#include<stdio.h>
#include<string.h>
#define MAXN 100002
int father[MAXN];
int record[MAXN];
int InitUnion()
{
int i;
for(i=0; i<MAXN; ++i)
{
father[i] = i;
record[i] = 0;
}
}
int find_set(int n)
{// 改成递归的形式<->爆栈
while(father[n] != n)
{
n = father[n];
}
return n;
}
int main()
{
int x, y, i, a, b, max=-1, flag = 0, cnt = 1, t;
InitUnion();
while(scanf("%d%d", &a, &b) == 2 && a != -1 && b != -1)
{
if(!a && !b)
{
if(cnt == 1)
printf("Yes\n");
else
{
if(flag) printf("No\n");
else
{
for(i=0, t=0; i<=max; ++i)
if(record[i] && father[i] == i) t++;
if(t > 1) flag = 1;
if(!flag) printf("Yes\n");
else printf("No\n");
}
InitUnion();
cnt = 1, flag = 0;
max = -1;
}
continue;
}
a--, b--;
cnt = 2;
max = max > b ? max : b;
max = max > a ? max : a;
record[a] = record[b] = 1;
x = find_set(a), y = find_set(b);
if(x == y) flag = 1;
else father[x] = y;
}
return 0;
}