链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1198
题目:
2 2 DK HF 3 3 ADC FJK IHE -1 -1
2 3
题目大意:
有A~K共9种类型的田地,每种田上面的水渠是不同的(它们连接的出口不同)。然后由这些类型的田组成一个n*m大小的更大的田,由于相邻两个田地的水渠可能可以相通(有接口),所以只要相通的那些田地只需要一个水源就可以了。求最少需要多少个水源。
分析:
可用bfs,dfs做,不过用并查集更方便点。 用并查集只需要判断一个田周围的四个田,如果有接口,那么就把这两个田合并成一棵树,最后判断几棵树即可。
代码:
// 并查集 #include<cstdio> #include<cstring> #define N 55 int n,m,f[N*N],rank[N*N]; int map[55][55]; // 左,上,右,下 int dir[4][2]={{0,-1},{-1,0},{0,1},{1,0}}; // 田的类型。 按顺序上,右,下,左,有出口的是1,无的是0 int farm[11][4]={ {1,0,0,1}, {1,1,0,0}, {0,0,1,1}, {0,1,1,0}, {1,0,1,0}, {0,1,0,1}, {1,1,0,1}, {1,0,1,1}, {0,1,1,1}, {1,1,1,0}, {1,1,1,1} }; inline void initSet(){ for(int i=0; i<N*N; ++i) f[i]=i,rank[i]=0; } int find(int x){ int i,j=x; while(j!=f[j]) j=f[j]; while(x!=j){ i=f[x]; f[x]=j; x=i; } return j; } void Union(int x,int y){ int a=find(x), b=find(y); if(a==b)return ; if(rank[a]>rank[b]) f[b]=a; else{ if(rank[a]==rank[b]) ++rank[b]; f[a]=b; } } int main(){ char ch; while(scanf("%d%d%*c",&n,&m)&&n>=1&&m>=1){ for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ scanf("%c",&ch); map[i][j]=ch-'A'; } getchar(); } initSet(); for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ for(int k=0; k<4; ++k){ int dx=i+dir[k][0],dy=j+dir[k][1]; if(dx<0||dx>=n||dy<0||dy>=m)continue; if(k==0){ // 左 if(farm[map[dx][dy]][1]&&farm[map[i][j]][3]){ Union(dx*m+dy, i*m+j); } } else if(k==1){ // 上 if(farm[map[dx][dy]][2]&&farm[map[i][j]][0]){ Union(dx*m+dy, i*m+j); } } else if(k==2){ // 右 if(farm[map[dx][dy]][3]&&farm[map[i][j]][1]){ Union(dx*m+dy, i*m+j); } } else if(k==3){ // 下 if(farm[map[dx][dy]][0]&&farm[map[i][j]][2]){ Union(dx*m+dy, i*m+j); } } } } } int cnt=0; for(int i=0; i<n*m; ++i) if(f[i]==i) ++cnt; printf("%d\n", cnt); } return 0; }
—— 生命的意义,在于赋予它意义。
原创 http://blog.csdn.net/shuangde800 , By D_Double (转载请标明)