USACO5.1.2 Starry Night(starry)

数据不大,但细节要注意。这道题的基本方法就是Floodfill,找到所有的连通块,把全等的连通块标识起来。

寻找全等连通块的方法很多,我的方法是把每个连通块散列存储起来。找到一个新的连通块的时候把它和旋转对称变换所得8个图形分别进行散列,然后在哈希表中查找是否出现过。如果出现过,新的连通块与以前的全等。如果没有出现,则找到了一个新的连通块,标识并存储即可。


/*
PROB: starry
LANG: C++
ID: xsy97051
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 1<<20
typedef char Ima[100][101];
int h,w;
Ima start,final;
struct node{
    Ima im;//图像 
    int ih,iw;//长 宽 
}hash[26];//存储图像 
int len;
int dir[][2]={{0,1},{1,-1},{-1,0},{-1,-1},{0,-1},{-1,1},{1,0},{1,1}};//方向向量 
Ima now;

void flood(Ima& ima,int i,int j,int cor[])//floodfill
{ 
    ima[i][j]='0'; now[i][j]='1';
    cor[0]=min(cor[0],i); 
    cor[1]=min(cor[1],j);
    cor[2]=max(cor[2],i); 
    cor[3]=max(cor[3],j);
    for(int k=0;k<8;k++)
    {
        int r,s;
        r=dir[k][0]+i; 
        s=dir[k][1]+j;
        if(r>=0 && r<h && s>=0 && s<w && ima[r][s]=='1')
            flood(ima,r,s,cor);
    }
}
 
node com;
void change()//旋转
{ 
    Ima a;
    memcpy(a,com.im,sizeof(a));
    for(int i=0;i<=com.ih;i++)
        for(int j=0;j<=com.iw;j++)
            com.im[j][com.ih-i]=a[i][j];
    swap(com.ih,com.iw); 
}

void turn()//对称
{ 
    for(int i=0;i<=com.ih/2;i++)
        for(int j=0;j<=com.iw;j++)
		{
			char t=com.im[i][j];
			com.im[i][j]=com.im[com.ih-i][j];
			com.im[com.ih-i][j]=t;
		}  
}
 
bool search(int cor[])//查找星座
{ 
    for(int r=0;r<2;r++)
    {
        if(r==1) turn();
        for(int s=0;s<4;s++)
        {
            if(s!=0) change();
            if(cor[2]-cor[0]!=com.ih || cor[3]-cor[1]!=com.iw) continue;
            bool flag=1;
            for(int i=cor[0];i<=cor[2] && flag;i++)
                for(int j=cor[1];j<=cor[3] && flag;j++)
                    if(com.im[i-cor[0]][j-cor[1]]!=now[i][j])
                    {
                        flag=0; break;
                    }
            if(flag==1) return 1;
        }
    }
    return 0;  
}
 
void insert(int cor[])//插入新星座
{ 
    for(int i=cor[0];i<=cor[2];i++)
        for(int j=cor[1];j<=cor[3];j++)
            hash[len].im[i-cor[0]][j-cor[1]]=now[i][j];
    
    hash[len].ih=cor[2]-cor[0];
    hash[len].iw=cor[3]-cor[1];
}
  
void col(int i,int j,int c)
{
    final[i][j]=(char)('a'+c);
    for(int k=0;k<8;k++)
    {
        int r,s;
        r=dir[k][0]+i; s=dir[k][1]+j;
        if(r>=0 && r<h && s>=0 && s<w && final[r][s]=='1')
            col(r,s,c);
    }
}

void init()
{
    cin>>w>>h;
    for(int i=0;i<h;i++)
        cin>>start[i];
    len=0;
    memcpy(final,start,sizeof(start));
    for(int i=0;i<h;i++)
    {
        for(int j=0;j<w;j++)
        {
            if(start[i][j]=='1'){
                memset(now,'0',sizeof(now));
                int cor[]={INF,INF,-1,-1};//星座大小 
                flood(start,i,j,cor);
                bool flag=0;
                int k=0;
                for(k;k<len;k++)
                {
                    memcpy(com.im,hash[k].im,sizeof(com.im));
                    com.ih=hash[k].ih; com.iw=hash[k].iw;
                    if(search(cor)) {flag=1; break;}
                }
                if(flag==0)	//查找不成功插入
                { 
                    memset(hash[len].im,'0',sizeof(start));
                    insert(cor);
                    len++;
                }
                col(i,j,k);//对刚才的星座染色 
            }
        }
    }
}

void outit()
{
	for(int i=0;i<h;i++)
	{
        for(int j=0;j<w;j++)
        	cout<<final[i][j];
        cout<<endl;
    }
}

int main()
{
	freopen("starry.in","r",stdin);
	freopen("starry.out","w",stdout);
	init();
	outit();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值