zoukankan      html  css  js  c++  java
  • UVA

    /*
      收获:
      1. 概念理解 图形的拓扑等价
      可见: http://www.baike.com/wiki/%E6%8B%93%E6%89%91
      
      摘取重点:
      在拓扑学里不讨论两个图形全等的概念,但是讨论拓扑等价的概念。比如,尽管圆和方形、三角形的形状、大小不同,在拓扑变换下,它们都是等价图形。在一个球面上任选一些点用不相交的线把它们连接起来,这样球面就被这些线分成许多块。在拓扑变换下,点、线、块的数目仍和原来的数目一样,这就是拓扑等价。一般地说,对于任意形状的闭曲面,只要不把曲面撕裂或割破,他的变换就是拓扑变换,就存在拓扑等价。
      
      2. 这个博客的讲解比较清晰:
      http://www.cnblogs.com/acm1314/p/4534360.html
      
      3. blog: http://blog.csdn.net/ecnu_lzj/article/details/71056490
      
      这个博客,通过举例子,解释清楚了一个问题:
      为什么上下左右,都要加上边界(这是为了,通过连通块的计算,来判断图里到底有几个洞)
      
      不过最终,由于这道题还是不怎么会写,所以我自己没能写出来,而是看懂了小白书上的代码后,按照书的配套代码的思路敲的
      
    */


    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <set>
    #define rep(i, n) for (int i = 0; i < (n); i++)
    using namespace std;
    
    char bin[256][5];
    const int maxh = 200 + 5;
    const int maxw = 50 * 4 + 5;
    int H, W, pic[maxh][maxw], color[maxh][maxw]; //col: color
    char line[maxw];
    const int dx[] = { -1, 1, 0, 0 };
    const int dy[] = { 0, 0, -1, 1 };
    //遍历连通块时用,对应的是四个方向的坐标变化量 
    vector<set<int> > neighbours;
    
    const char code[] = "WAKJSD";
    //通过黑连通块的序号,找到它内部的白连通块个数(即:象形文字内的洞的个数),最终返回洞数所对应的字母 
    char change(int c)
    {
    	int cnt = neighbours[c].size();
    	return code[cnt];
    }
    
    void print() //这个函数可以用来做测试,看十六进制转换为二进制以后,转换结果是否正确 
    {
    	rep(i, H)
    	{
    		rep(j, W) printf("%d", pic[i][j]);
    		printf("
    ");
    	}
    }
    
    void decode (char ch, int row, int col)
    {
    	rep(i, 4)
    	pic[row][col + i] = bin[ch][i] - '0'; //把每个十六进制字符,转为二进制时,一个字符变为对应变为四个字符
    }
    bool isin(int x, int y)
    {
    	return x >= 0 && x < H && y >= 0 && y < W;
    }
    bool isok(int x, int y) //判断 (x, y)是否在迷宫区域内,且尚未被染色 
    {
    	return isin(x, y) && !color[x][y];
    }
    
    
    //从位置(row, col)开始进行dfs,并将与之相邻的整个连通块,设置为颜色c 
    void dfs(int row, int col, int c)
    {
    	color[row][col] = c;
    	rep(i, 4)
    	{
    		int row2 = row + dx[i];
    		int col2 = col + dy[i];
    		if (isok(row2, col2) && pic[row2][col2] == pic[row][col]) //判断对应位置二进制数码是否一致
    		dfs(row2, col2, c); 
    	}
    }
    
    void check_neighbours(int row, int col)
    {
    	rep(i, 4)
    	{
    		int row2 = row + dx[i], col2 = col + dy[i];
    		if (isin(row2, col2) && !pic[row2][col2] && color[row2][col2] != 1)
    		neighbours[color[row][col]].insert(color[row2][col2]);
    		//cnt为1的一圈(因为经过了color数组的赋值,所以也即为,color数组中,对应元素为1的圈) 其实是象形文字的最外圈,也就是我们加的四周边界,以及,四周边界和象形文字之间,还会有一些区域和四周边界连接,这整个的连通块,其实和象形文字本身无关,故而不做处理
    	}
    }
    
    int main()
    {
    	strcpy(bin['0'], "0000"); //用来将十六进制转换为二进制,很巧妙的方法,就是先将十六进制对应的二进制字符存好,到时就可以直接使用了 
    	strcpy(bin['1'], "0001");
    	strcpy(bin['2'], "0010");
    	strcpy(bin['3'], "0011");
    	strcpy(bin['4'], "0100");
    	strcpy(bin['5'], "0101");
    	strcpy(bin['6'], "0110"); 
    	strcpy(bin['7'], "0111");
    	strcpy(bin['8'], "1000");
    	strcpy(bin['9'], "1001");
    	strcpy(bin['a'], "1010");
    	strcpy(bin['b'], "1011");
    	strcpy(bin['c'], "1100");
    	strcpy(bin['d'], "1101");
    	strcpy(bin['e'], "1110");
    	strcpy(bin['f'], "1111");
    	
    	int kase = 0;
    	while (scanf("%d%d", &H, &W) == 2 && H)
    	{
    		memset(pic, 0, sizeof(pic));
    		rep(i, H)
    		{
    			scanf("%s", line);
    			rep(j, W)
    			decode (line[j], i + 1, j * 4 + 1); //将十六进制的输入,转换为其对应的二进制,因而每个char,将会转换为4个字符 
    		}
    		
    		H += 2;
    		W = W * 4 + 2; //上下左右方向,都要在最外层加边界。否则在统计连通块时,有可能会在特殊的图形分布处出错
    		
    		int cnt = 0;
    		vector<int> cc; //对应二进制数位为1的连通块 (connnected components)
    		memset(color, 0, sizeof(color));
    		rep(i, H)
    		rep(j, W)
    		if (!color[i][j])
    		{
    			dfs(i, j, ++cnt);
    			if (pic[i][j] == 1) cc.push_back(cnt);
    			//扫描整个区域,遍历找到所有连通块,并为同一连通块的格子,标上相同的编号。同时,把黑连通块存进 vector cc中 
    		} 
    		
    		neighbours.clear();
    		neighbours.resize(cnt + 1);
    		//neighbours vector中,存放的是int型集合,所以最好先自己 resize设置大小
    		//之所以要 +1,是因为有 dfs(i, j, ++cnt); 使得cnt其实是从1开始的,而不是0;而cnt的意义,恰好是当前的黑色连通块个数,而这样的设定,和vector中的下标的意义是有区别的(毕竟前者从1开始,后者从0开始),这点在设置vector的大小时,要尤其注意 
    		
    		rep(i, H)
    		rep(j, W)
    		{
    			if (pic[i][j] == 1)
    			check_neighbours(i, j);
    			//扫描整个图形中的黑点,并把该点旁边的白色连通块(白色连通块个数,就代表了洞数)存入 vector neighbours
    			//vector中的下标,恰好是黑点对应的连通块的编号
    		}
    		
    			vector<char> ans;
    			rep(i, cc.size())
    				ans.push_back(change(cc[i]));
    			sort(ans.begin(), ans.end());	
    			
    			printf("Case %d: ", ++kase);
    			rep(i, ans.size()) printf("%c", ans[i]);
    			printf("
    ");
    	}
    	return 0;
    }

  • 相关阅读:
    【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
    【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
    【Java EE 学习 35 上】【strus2】【类型转换器】【struts2和Servlet API解耦】【国际化问题】【资源文件乱码问题已经解决】
    【Java EE 学习 34】【struts2学习第一天】
    【JavaScript中的正则表达式】
    【Java EE 学习 33 下】【validate表单验证插件】
    【Java EE 学习 33 上】【JQuery样式操作】【JQuery中的Ajax操作】【JQuery中的XML操作】
    【Java EE 学习 32 下】【JQuery】【JQuey中的DOM操作】
    【Java EE 学习 32 上】【JQuery】【选择器】
    【Java EE 学习 31】【JavaScript基础增强】【Ajax基础】【Json基础】
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789396.html
Copyright © 2011-2022 走看看