HDU-1198-Farm Irrigation
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1198
程序分析:
题意就是说有一块大田,分为很多小块的,其中每块田都有各种各样形状的水渠,现要灌溉整块大田,问需要多少个水源可以完成。给你那些小田的水渠形状图,最多有上下左右四个方向可以把水输出去。
解决方法:
并查集思想,能合并的就合并为一块田,这样总能灌溉到了吧,哪么,能合并的条件是什么?对应方向可以把水渠对上去就可以合并。
可以用矩阵来存储每一块田的位置编号和图的编号,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 const int Max = 55; 6 int Far[Max*Max]; 7 int Rank[Max*Max]; 8 int Sign[Max*Max]; 9 int Map[Max][Max]; 10 int Flag[Max][Max]; 11 12 class Node 13 { 14 public: 15 Node(int u, int d, int l, int r):up(u),down(d),left(l),right(r) 16 { } 17 int up; //上 18 int down; //下 19 int left; //左 20 int right; //右 21 }; 22 23 Node Farm[12] = { 24 Node(0,0,0,0), //空 25 Node(1,0,1,0), //A 26 Node(1,0,0,1), //B 27 Node(0,1,1,0), //C 28 Node(0,1,0,1), //D 29 Node(1,1,0,0), //E 30 Node(0,0,1,1), //F 31 Node(1,0,1,1), //G 32 Node(1,1,1,0), //H 33 Node(0,1,1,1), //I 34 Node(1,1,0,1), //J 35 Node(1,1,1,1) //K 36 }; 37 38 39 void Make_set(int n) 40 { 41 int i; 42 for(i=0; i<=n*n; i++) 43 { 44 Far[i] = i; 45 } 46 memset(Rank, 0, sizeof(Rank)); 47 memset(Sign, 0, sizeof(Sign)); 48 } 49 50 int Find_set(int x) 51 { 52 if(Far[x] != x) 53 return Far[x] = Find_set(Far[x]); 54 return Far[x]; 55 } 56 57 void Unio(int a, int b) 58 { 59 a = Find_set(a); 60 b = Find_set(b); 61 if(a == b) 62 return; 63 if(Rank[a] < Rank[b]) 64 Far[a] = b; 65 else if(Rank[a] > Rank[b]) 66 Far[b] = a; 67 else 68 { 69 Far[a] = b; 70 Rank[b]++; 71 } 72 } 73 74 int main() 75 { 76 int m, n; 77 int k, up, left; 78 while(cin>>m>>n && m!=-1 && n!=-1) 79 { 80 Make_set(Max); 81 memset(Map, 0, sizeof(Max)); 82 string str; 83 int ans = 1; 84 for(int i=1; i<=m; i++) 85 { 86 cin>>str; 87 88 //合并 89 for(int j=1; j<=n; j++) 90 { 91 Flag[i][j] = ans++; 92 k = str[j-1]-'A'+1; 93 up = Map[i-1][j]; 94 left = Map[i][j-1]; 95 Map[i][j] = k; 96 //只跟上面的和左边的比较,可以合并就把他们所在块的代表数字合并 97 if(Farm[up].down == 1 && Farm[k].up == 1) 98 Unio(Flag[i-1][j], Flag[i][j]); 99 if(Farm[left].right == 1 && Farm[k].left == 1) 100 Unio(Flag[i][j-1], Flag[i][j]); 101 } 102 } 103 104 //统计 105 int count = 0; //记录有多少块分开的田 106 for(int z=1; z<ans; z++) 107 { 108 if(Find_set(z) == z) 109 count++; 110 } 111 cout<<count<<endl; 112 } 113 return 0; 114 }