链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2412
题意:有11种不同的水管,如果它们能连通,则可以流水,求一块地上连通水管数。
思路:这题主要是先要把不同的水管表示出来,一开始觉得要表示出来很麻烦,后面去看了别人写的。地有四个方向,某个方向上有水管则为1,没有为0,这样就表示出来了。然后在搜索过程中,如果当前的地在某个方向i上有水管,则看相邻的地在对应的方向(i+2)%4上有无水管,有的话继续搜下去,没有就不搜咯。其他部分和zoj的1709差不多,用一个visited数组来记录某块地有没有被搜过,0为没被搜,1为被搜过。
#include<cstdio> #include<cstring> const int maxn=52; int map[maxn][maxn]; int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; int type[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}};//水管类型 int m,n; int visited[maxn][maxn]; void dfs(int x,int y) { visited[x][y]=1; int xx,yy; for(int i=0;i<4;i++) { if(type[map[x][y]][i]==0) continue; xx=x+dir[i][0];yy=y+dir[i][1]; if(xx<0 || xx>=m || yy<0 || yy>=n) continue; if(visited[xx][yy]==1) continue; if(type[map[xx][yy]][(i+2)%4]==1) dfs(xx,yy); } } int main() { int cnt; char c; while(scanf("%d%d",&m,&n) && m>0 && n>0) { memset(visited,0,sizeof(visited)); cnt=0; getchar(); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { scanf("%c",&c); map[i][j]=c-'A';//变为数字 } getchar(); } for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(visited[i][j]==0) { dfs(i,j); cnt++; } printf("%d\n",cnt); } return 0; }
在写的过程中老是有些小错误,表示很内伤啊。。。。
下面的代码是用了map来把字母A,B等映射为数字。功能和上面的map[i][j]=c-'A'一样。纯属无聊。
#include<cstdio> #include<cstring> #include<map> using namespace std; const int maxn=52; int s[maxn][maxn]; int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; int type[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}};//水管类型 map<char,int> ma; int m,n; int visited[maxn][maxn]; void dfs(int x,int y) { visited[x][y]=1; int xx,yy; for(int i=0;i<4;i++) { if(type[s[x][y]][i]==0) continue; xx=x+dir[i][0];yy=y+dir[i][1]; if(xx<0 || xx>=m || yy<0 || yy>=n) continue; if(visited[xx][yy]==1) continue; if(type[s[xx][yy]][(i+2)%4]==1) dfs(xx,yy); } } int main() { int cnt; char c; for(int i=0;i<11;i++) { ma['A'+i]=i; } while(scanf("%d%d",&m,&n) && m>0 && n>0) { memset(visited,0,sizeof(visited)); cnt=0; getchar(); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { scanf("%c",&c); s[i][j]=ma[c];//变为数字 } getchar(); } for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(visited[i][j]==0) { dfs(i,j); cnt++; } printf("%d\n",cnt); } return 0; }
另外,此题用并查集做也可以。还是要先把11种水管表示出来,然后可以连通的水管就合并在一个集合中,统计各个集合中元素个数,再求和。代码就不写了。
究竟是我抛弃了历史,还是历史遗弃了我。