1 hdu 1232 题目网址
题意:实现任意两个城镇有道路相通,已经修建部分道路,问至少还需修建多少条道路。
思路:连通分量的个数-1
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 1000 ;
int fa[maxn] , t[maxn] ;
int Find(int x)
{
while(x != fa[x])
{
fa[x] = fa[fa[x]] ;
x = fa[x] ;
}
return x ;
}
void Union(int x , int y)
{
int fx = Find(x) ;
int fy = Find(y) ;
if(fx != fy)
fa[fy] = fx ;
}
int main()
{
int N , M , a, b;
while(scanf("%d" , &N)!= EOF &&N)
{
scanf("%d" , &M) ;
for(int i = 1 ; i <= N ; i ++)
fa[i] = i ;
for(int i =0 ; i < M ; i++)
{
scanf("%d%d" , &a ,&b) ;
Union(a ,b) ;
}
memset(t , 0 , sizeof(t) ) ;
for(int i = 1 ; i <= N ; i++)
t[Find(i)] = 1 ;
int ans = 0 ;
for(int i = 1 ; i <= N ; i++)
if(t[i]) ans++ ;
printf("%d\n" , ans - 1) ;
}
return 0;
}
hdu 1213 题目网址
题意: 有n个人, 每一桌上的人都相互认识(认识关系可传递),至少需要多少桌可使所有人都坐下
思路:求连通分量数
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 1000 ;
int fa[maxn] , t[maxn] ;
int Find(int x)
{
while(x != fa[x])
{
fa[x] = fa[fa[x]] ;
x = fa[x] ;
}
return x ;
}
void Union(int x , int y)
{
int fx = Find(x) ;
int fy = Find(y) ;
if(fx != fy)
fa[fy] = fx ;
}
int main()
{
int T , N , M , a , b;
scanf("%d" , &T) ;
for(int i = 1 ; i <= T ; i++)
{
scanf("%d%d" , &N, &M) ;
for(int i = 1 ; i <= N ; i++)
fa[i] = i ;
while(M --)
{
scanf("%d%d" , &a, &b) ;
Union(a, b) ;
}
memset(t , 0 , sizeof(t)) ;
for(int i = 1 ; i <= N ; i++)
t[Find(i)] = 1 ;
int ans = 0 ;
for(int i = 1 ; i <= N ; i++)
if(t[i]) ans ++ ;
printf("%d\n" ,ans) ;
}
return 0 ;
}
hdu 1598 题目链接
题意:XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级空中漫游结构)进行交流,每条SARS都对行驶在上面的Flycar限制了固定的Speed,同时XX星人对 Flycar的“舒适度”有特殊要求,即乘坐过程中最高速度与最低速度的差越小乘坐越舒服 ,(理解为SARS的限速要求,flycar必须瞬间提速/降速,痛苦呀 ),
但XX星人对时间却没那么多要求。要你找出一条城市间的最舒适的路径。(SARS是双向的)。
思路:贪心+并查集,对所有道路按照速度进行排序,不断添加道路,当a , b连通时,取道路速度差的最小值。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define Min(a,b) ( (a) < (b) ? (a) : (b) )
const int maxn = 1005 , inf = 1e9;
int fa[205] , n , MIN;
struct Edge
{
int s , t ;
int speed ;
};
bool cmp(Edge a , Edge b)
{
return a.speed < b.speed ;
}
Edge e[maxn] ;
void init(int n)
{
for(int i =1 ; i <= n ; i ++)
fa[i] = i ;
}
int Find(int a)
{
while(a != fa[a])
{
fa[a] = fa[fa[a]] ;
a = fa[a] ;
}
return a ;
}
void Union(int x ,int y)
{
int fx = Find(x) ;
int fy = Find(y) ;
if(fx != fy)
fa[fy] = fx ;
}
int main()
{
int m , a ,b ,q ;
while(scanf("%d%d" , &n ,&m) != EOF)
{
for(int i = 0 ; i < m ; i++)
scanf("%d%d%d" , &e[i].s , &e[i].t , &e[i].speed) ;
sort(e , e + m , cmp) ;
scanf("%d" , &q) ;
while(q--)
{
scanf("%d%d" , &a, &b) ;
MIN = inf ;
for(int i = 0; i < m ; i ++)
{
init(n) ;
for(int j = i ; j < m ; j ++)
{
Union(e[j].s , e[j].t) ;
if(Find(a) == Find(b))
{
MIN = Min(MIN , e[j].speed - e[i].speed) ;
break ;
}
}
}
if(MIN == inf)
printf("-1\n" ) ;
else
printf("%d\n" , MIN) ;
}
}
return 0;
}
hdu1856 题目链接
题意:求最大的连通分量的大小
#include<stdio.h>
#define N 10000000
int pre[N],num[N];
int find(int x){
int r=x,k=x,j;
while(pre[r]!=r)
r=pre[r];
while(k!=r){
j=pre[k];
pre[k]=r;
k=j;
}
return r;
}
int join(int x,int y){
int fx,fy;
fx=find(x);
fy=find(y);
if(fx!=fy){
pre[fx]=fy;
num[fy]+=num[fx];
}
return 0;
}
int main(){
int n,x,y,i,j;
while(scanf("%d",&n)!=EOF){
for(i=1;i<=N;i++){
pre[i]=i;
num[i]=1;
}
while(n--){
scanf("%d%d",&x,&y);
join(x,y);
}
int max=1;
for(j=1;j<=N;j++){
if(num[j]>max)
max=num[j];
}
printf("%d\n",max);
}
return 0;
}
hdu1272 题目链接
题意: 任意两个节若满足有且仅有一条道路相通,则输出“Yes”,否则输出“No”
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 100005 ;
int edgenum = 0;
int f[maxn] , vis[maxn] ;
void Init()
{
for(int i = 1 ; i <= 100000 ; i ++)
f[i] = i ;
}
int Find(int x)
{
while(x != f[x])
{
f[x] ==f[f[x]] ;
x = f[x] ;
}
return x ;
}
void Union(int x , int y)
{
int fx = Find(x) ;
int fy = Find(y) ;
if(fx != fy)
{
f[fy] = fx ;
edgenum ++ ;
}
}
int main()
{
//freopen("a.txt" , "r" , stdin) ;
int ok , x , y , n = 0 , m = 1000000;
while(scanf("%d%d" , &x , &y) != EOF )
{
memset(vis , 0 , sizeof(vis) ) ;
edgenum = 0 ;
n = 0 ;
if( x == -1 && y == -1) break ;
if (x == 0 && y == 0 )
{
printf("Yes\n") ; continue ;
}
Init() ;
Union(x , y) ;
vis[x] = 1 , vis[y] = 1 ;
ok = 1 ;
while(scanf("%d%d" , &x ,&y)!= EOF )
{
if(x == 0 && y == 0) break ;
if(Find(x) == Find(y))
{ ok = 0 ;Union(x ,y ) ;}
else Union(x ,y ) ;
vis[x] = 1 , vis[y] = 1 ;
}
int vnum = 0 ;
for(int i = 1 ; i <= 100000 ; i ++)
{
if(vis[i]) vnum ++ ;
}
if(vnum != edgenum + 1) ok = 0 ;
if(ok ) printf("Yes\n") ;
else printf("No\n") ;
}
return 0;
}
hdu 5606
链接
题意:n个节点n - 1条边,每条边的权值为0或1,求所有节点i(1 <= i <= n)离节点i最近的节点的数目,并对它们异或操作后输出
思路:求所有连通分量的大小,并对他们进行异或操作
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int fa[maxn] , ans[maxn] ;
void Init()
{
for(int i = 1 ; i <= 100000 ; i ++)
{
fa[i] = i ;
ans[i] = 1 ;
}
}
int Find(int x)
{
if(x == fa[x]) return x ;
else return fa[x] = Find(fa[x]) ;
}
int Union(int x , int y)
{
int fx = Find(x) ;
int fy = Find(y) ;
if(fx != fy)
{
fa[fy] = fx ;
ans[fx] += ans[fy] ;
//ans[fy] = ans[fx] ;
}
return 0 ;
}
int Xor( int a , int b)
{
return (!a && b) || (a && !b) ;
}
int main()
{
//freopen("a.txt" , "r" , stdin) ;
int t , n , u , v , w ;
scanf("%d" , &t) ;
while(t --)
{
scanf("%d" , &n) ;
Init() ;
for(int i = 1 ; i <= n -1 ; i ++)
{
scanf("%d%d%d" , &u , &v , &w) ;
if(w == 0) Union(u , v) ; //权值为0时,为一个连通分量
}
for(int i = 1 ; i <= n ; i ++) //更新所有的连通分量大小
{
int k = Find(i) ;
ans[i] = ans[k] ;
}
int Ans = ans[1];
for(int i = 2 ; i <= n ; i ++)
{
Ans = Ans ^ ans[i] ;
}
printf("%d\n" , Ans) ;
}
return 0;
}
hdu1198 稍微复杂的连通分量表示 链接
题意:有11种不同形状的管道,一块田用这11种不同形状的管道覆盖,问这块田中有多少连通分量
思路:本题难点是如何表示连通分量,集合的合并操作怎么表示
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 1000 ;
int type[11][4] =
{
{1 , 0 , 1 , 0} ,
{0 , 1 , 1 , 0} ,
{1 , 0 , 0 , 1} ,
{0 , 1 , 0 , 1} ,
{0 , 0 , 1 , 1} ,
{1 , 1 , 0 , 0} ,
{1 , 1 , 1 , 0} ,
{1 , 0 , 1 , 1} ,
{1 , 1 , 0 , 1} ,
{0 , 1 , 1 , 1} ,
{1 , 1 , 1 , 1}
} ;
char Farm[maxn][maxn] ;
int fa[maxn*maxn + 10] ;
int cnt , m , n ;
void Init(int n)
{
for(int i = 1 ; i <=n ; i ++)
fa[i] = i ;
cnt = n ;
}
int Find(int x)
{
if(x == fa[x]) return x ;
else return fa[x] = Find(fa[x]) ;
}
void Union(int ax , int ay , int bx , int by , int dir)
{
if(ax > m || bx > m ) return ;
if(ay > n || by > n ) return ;
int a = Farm[ax][ay] - 'A' ;
int b = Farm[bx][by] - 'A' ;
bool flag = false ;
if(dir == 0)
{
if(type[a][1] && type[b][0]) flag = true ;
}
else
{
if(type[a][3] && type[b][2]) flag = true ;
}
if(flag )
{
int fx = Find( (ax - 1) * n + ay) ;
int fy = Find( (bx - 1) * n + by) ;
if(fx != fy)
{
fa[fx] = fy ;
-- cnt ;
}
}
}
int main()
{
//freopen("a.txt" , "r" , stdin) ;
while(scanf("%d%d" , &m , &n) != EOF)
{
if(n <0 || m < 0) break ;
Init(n * m) ;
for(int i = 1 ; i <= m ; i ++)
scanf("%s" , Farm[i] + 1) ;
for(int i = 1 ; i <= m ; i ++)
{
for(int j = 1 ; j <= n ; j ++)
{
Union(i , j , i + 1 , j , 1) ;
Union(i , j , i , j + 1 , 0) ;
}
}
printf("%d\n" , cnt) ;
}
return 0 ;
}
hdu2473 链接
并查集的删除操作
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <set>
#pragma comment(linker, “/STACK:1024000000,1024000000”)
using namespace std;
const int maxn = 1100006 ;
int fa[maxn] , id[maxn] ;
set<int> S ;
int Find(int x)
{
if(x == fa[x]) return x ;
else return fa[x] = Find(fa[x]) ;
}
void Union(int x ,int y)
{
int fx = Find(id[x]) ;
int fy = Find(id[y]) ;
if(fx != fy)
fa[fx] = fy ;
}
int main()
{
//freopen("a.txt", "r" , stdin) ;
int n , m , kase = 0 , x , y , cnt ;
char s[10] ;
while(scanf("%d%d" , &n , &m) != EOF)
{ S.clear() ;
if(n == 0 && m == 0) break ;
cnt = n ;
for(int i = 0 ; i < maxn ; i ++)
fa[i] = i ;
for(int i = 0 ; i < n ; i ++)
id[i] = i ;
for(int i = 1 ; i <= m ; i ++)
{
scanf("%s" , s) ;
if(s[0] == 'M')
{
scanf("%d%d" , &x , &y ) ;
Union(x , y) ;
}
if(s[0] == 'S')
{
scanf("%d" , &x) ;
id[x] = cnt ++ ;
//fa[id[x]]=id[x];
}
}
for(int i = 0 ; i < n ; i ++)
{
S.insert(Find(id[i])) ;
//printf("%d " , Find(id[i])) ;
}
//printf("\n") ;
printf("Case #%d: %d\n" , ++kase , S.size()) ;
}
return 0;
}