zoukankan      html  css  js  c++  java
  • 洛谷P2749 [USACO5.1]夜空繁星Starry Night

    零、洛谷链接

    一、简要题意

    给你一张图,要找出所有八连通的连通块,规定不管旋转翻转后,只要相同的两个连通块算为同一种连通块。

    对相同连通块染相同一个小写字母,按字典序输出染色后的图。

    下面八个全为同一种连通块。

    二、解法 + code

    我们可以看出,本题最大的难点在于如何判断相似。

    根据小学玄学知识&样例,我们有一些发现:

    两个相似的图,从同一个点到别的点的直线距离(曼哈顿距离)相等。

    来张图:

    但是,我们在走连通块时,由于旋转和翻转的关系,并不能保障任意选择两点就是同一个点。

    一看数据范围:(n≤100)

    因此,可以将所有的点到其他点的曼哈顿距离都算出来,再加在一块求和,以这个数值作为比较相似的因素即可。

    似乎是解决了?

    快乐地把代码写出来♪:

    // 仅放核心代码:
    int main()
    {
    	scanf("%d%d", &m, &n);
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			cin >> mapp[i][j];
    		}
    	}
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			if(mapp[i][j] == '1')
    			{
    				tempcnt = 0;
    				long long tempsum = 0;
    				bfs(i, j); 
    				rep(k, 1, tempcnt)
    				{
    					rep(l, 1, tempcnt)
    					{
    						tempsum += sqrt(abs(temp[k].x - temp[l].x) * abs(temp[k].x - temp[l].x) + abs(temp[k].y - temp[l].y) * abs(temp[k].y - temp[l].y));
    					}
    			//	cout << tempsum  << endl;
    				}
    			//	cout << "tempcnt:" << tempcnt << endl;
    				int f = 0; 
    				rep(k, 1, cnt)
    				{
    			
    					if(tempsum == hhash[k])
    					{
    						f = 1;
    						color(i, j, k); 
    						break;
    					} 
    				}
    				if(!f)
    				{
    					hhash[++cnt] = tempsum; 
    				//	cout << cnt << endl;
    					color(i, j, cnt);
    				}
    			}
    		}
    	}
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			printf("%c", mapp[i][j]);
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    
    
    结果:

    干得漂亮,有60分了

    我们再来思考:因为曼哈顿距离带了根号,而这个代码里面全部取整了,所以两个仅有一点差别的图就会挂掉。、

    所以带个double试试?

    // by pjx Feb.
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <stack>
    #define REP(i, x, y) for(register int i = x; i < y; i++)
    #define rep(i, x, y) for(register int i = x; i <= y; i++)
    #define PER(i, x, y) for(register int i = x; i > y; i--)
    #define per(i, x, y) for(register int i = x; i >= y; i--)
    using namespace std;
    const int N = 605; 
    int n, m, tempcnt;
    char mapp[N][N];
    double hhash[N], tempsum;
    int cnt;
    int dx[] = {0, -1, -1, -1, 0, 0, 1, 1, 1};//八个方向 
    int dy[] = {0, -1, 0, 1, -1, 1, -1, 0, 1};
    queue <int> qx, qy;
    struct node{//用来存连通块每个点的坐标 
    	int x, y;
    }temp[N * N];
    void bfs(int x, int y)//搜索连通块 
    {
    	temp[++tempcnt].x = x;
    	temp[tempcnt].y = y;
    	qx.push(x);
    	qy.push(y);
    	mapp[x][y] = '2';//如果搜到了一个点,那把它标记为未染色过但搜索过 
    	while(!qx.empty())
    	{
    		int tx = qx.front();
    		int ty = qy.front();
    		qx.pop();
    		qy.pop();
    		rep(i, 1, 8)
    		{
    			int xx = tx + dx[i];
    			int yy = ty + dy[i];
    			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && mapp[xx][yy] == '1')
    			{
    				mapp[xx][yy] = '2';
    				qx.push(xx);
    				qy.push(yy);
    				temp[++tempcnt].x = xx;
    				temp[tempcnt].y = yy;				 
    			}
    		}
    	}
    }
    void color(int x, int y, int word)//给这个图重新染色 
    {
    	qx.push(x);
    	qy.push(y);
    	mapp[x][y] = char(word + 'a' - 1);
    	while(!qx.empty())
    	{
    		int tx = qx.front();
    		int ty = qy.front();
    		qx.pop();
    		qy.pop();
    		rep(i, 1, 8)
    		{
    			int xx = tx + dx[i];
    			int yy = ty + dy[i];
    			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && mapp[xx][yy] == '2')
    			{
    				mapp[xx][yy] = char(word + 'a' - 1);
    				qx.push(xx);
    				qy.push(yy);				 
    			}
    		}
    	}
    }
    bool check()//判断两个连通块是否为同一种 
    {
        tempsum = 0.0000;
        for(int k = 1; k <= tempcnt; k++)
    	{
    	    for(int l = 1; l <= tempcnt; l++)
    		{
    			tempsum += sqrt(double(abs(temp[k].x - temp[l].x)) * double(abs(temp[k].x - temp[l].x)) + double(abs(temp[k].y - temp[l].y)) * double(abs(temp[k].y - temp[l].y)));
    			//因为带根号,为了更加精确,保留4位小数 
    		}
    	}
    	for(int k = 1; k <= cnt; k++)
    	{
    		if(abs(tempsum - hhash[k]) <= 0.0001)//如果以前找到过与其总和一样的,就表明是第k种连通块 
    		{
    		    return 1;
    		} 
    	}
    	return 0; 
    
    }
    int main()
    {
    	scanf("%d%d", &m, &n);
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			cin >> mapp[i][j];
    		}
    	}
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			if(mapp[i][j] == '1')
    			{
    				tempcnt = 0;
    				bfs(i, j); 
                    if(check())
                    {
                       	for(int k = 1; k <= cnt; k++)
    					{
    						if(abs(tempsum - hhash[k]) <= 0.0001)//如果以前找到过与其总和一样的,就表明是第k种连通块 
    						{
    						    color(i, j, k);//染第k种颜色 
    						    break;
    						} 
    					} 
                    }
                	else//否则,增加新的一种,染新的一种颜色 
                	{
                	    hhash[++cnt] = double(tempsum); 
    	              	color(i, j, cnt);
    	           }
    			}
    		}
    	}
    	rep(i, 1, n)
    	{
    		rep(j, 1, m)
    		{
    			printf("%c", mapp[i][j]);
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    
    

    nice过了

  • 相关阅读:
    网络测量中基于Sketch方法的简单介绍
    Reading SBAR SDN flow-Based monitoring and Application Recognition
    Reading Meticulous Measurement of Control Packets in SDN
    Reading SketchVisor Robust Network Measurement for Sofeware Packet Processing
    ovs加dpdk在日志中查看更多运行细节的方法
    后缀数组
    (转载)LCA问题的Tarjan算法
    Codeforces Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) A. Checking the Calendar(水题)
    Vijos 1816统计数字(计数排序)
    卡特兰数
  • 原文地址:https://www.cnblogs.com/pjxpjx/p/14488943.html
Copyright © 2011-2022 走看看