NKOI 2440 数字消除游戏
来源:互联网 发布:淘宝卖的信用卡套现 编辑:程序博客网 时间:2024/06/07 00:41
数字消除游戏
问题描述
在一个n*n的方形棋盘上玩消除游戏,棋盘上布满了数字。每一步,玩家可以任选一个数字x,用它填充坐标为(1,1)格子所在连通区域,该区域的数字都会变成x。(如果两个数字相同且相邻,我们称这两个数字连通。相邻是上下左右四方向)。
当整个棋盘的数字都相同时,就可以将整个棋盘上的数字消除掉,游戏结束。
问,最少需要几次操作就能消除所有数字。
输入格式
有若干组测试数据(不超过20组),对于每组测试数据:
第一行,一个整数n,表示棋盘的尺寸。
接下来一个n*n的数字矩阵,表示游戏的初始局面。
当输入的n==0时,输入结束。
输出格式
对于每组测试数据,输出一行,一个整数,表示最少需要的操作数。
样例输入
21 3
3 3
4
5 5 2 0
5 5 2 0
2 2 2 0
0 0 0 2
0
样例输出
13
提示
样例说明,对于第二组数据:
第1步 选数字2去填充,得到:
2 2 2 0
2 2 2 0
2 2 2 0
0 0 0 2
第2步 选数字0去填充,得到:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 2
第3步 选数字2去填充,得到:
2 2 2 2
2 2 2 2
2 2 2 2
2 2 2 2
对于100%的数据,n<=8,
初始棋盘中最多有6种不同的数字
思路:枚举每次选取了哪种数字,然后找出左上角的格子所在的联通块,改变数字。
由于步数的不确定,应该使用迭代加深搜索
加入一个小剪枝:如果改变数字后,左上角格子所在的联通块大小没有改变,可以剪枝。这样可以避免来回往复地搜索。
采用IDA*算法,设计估价函数。可以发现如果当前矩阵中除了左上角的联通块之外,共有M种数字,那么还需要的步数不小于M。因此如果当前搜索深度+估价函数的值>深度限制,可以回溯。
我们可以发现,每次寻找左上角的格子所在的联通块耗费的时间常数巨大。因此我们在这里寻求突破。
我们引入一个N*N的v数组。左上角的格子所在的联通块里的格子标记为1。左上角联通块周围一圈格子标记为2,其它格子标记为0。如果某次选择了数字c,我们只需要找出标记为2并且数字为c的格子,向四周扩展,并相应地修改v标记,就可以不断扩大标记为1的区域,最终如果所有格子标记都是1,那么显然找到了答案。
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cstdlib>using namespace std;const int inf=1e9;inline void _read(int &x){ char t=getchar();bool sign=true; while(t<'0'||t>'9') {if(t=='-')sign=false;t=getchar();} for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0'; if(!sign)x=-x;}int dx[4]={-1,1,0,0};int dy[4]={0,0,-1,1};int n,vis[6],s[10][10],v[10][10],depth;int geth(){int i,j,temp=0;memset(vis,0,sizeof(vis));for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(!vis[s[i][j]]&&v[i][j]!=1){ vis[s[i][j]]=1; temp++;}return temp;}void paint(int x,int y,int c){v[x][y]=1;for(int i=0;i<4;i++){int tx=x+dx[i],ty=y+dy[i];if(tx<1||tx>n||ty<1||ty>n||v[tx][ty]==1)continue;v[tx][ty]=2;if(s[tx][ty]==c)paint(tx,ty,c);}}int check(int c){int i,temp=0,j;for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(v[i][j]==2&&s[i][j]==c){ temp++; paint(i,j,c); }return temp;}bool dfs(int k){int h=geth();if(k+h>depth)return 0;if(h==0)return 1;int res[10][10],i;for(i=0;i<=5;i++){memcpy(res,v,sizeof(v));if(check(i)&&dfs(k+1))return 1;memcpy(v,res,sizeof(res));}return 0;}int main(){while(cin>>n&&n){for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&s[i][j]);memset(v,0,sizeof(v));paint(1,1,s[1][1]);for(depth=0;;depth++) if(dfs(0))break;printf("%d\n",depth);}}
1 0
- NKOI 2440 数字消除游戏
- 数字消除游戏
- P2440数字消除游戏
- NKOI 1023 生命游戏
- NKOI 2222 开关游戏
- NKOI 2090 游戏
- NKOI 3744 智力游戏
- NKOI 3081 追赶游戏
- 【题&结论(递归标连通块)】【搜索(IDA*)】NKOJ 2440 数字消除游戏
- NKOI 1688 移字母游戏
- 消除游戏
- 消除游戏之消除算法
- 消除重复数字
- 消除重复数字
- HTML5 Canvas消除游戏
- C# 消除游戏
- 三消除游戏
- 消除类游戏
- Opera浏览器同步服务被黑,百万用户密码遭泄露
- C# 并发集合
- vim 脚本测试
- 管线命令
- iOS事件分发机制
- NKOI 2440 数字消除游戏
- 顶点漫反射.Shader
- spark的安装和使用
- JSON/XML解析
- 排序算法--冒泡排序,归并排序,快速排序
- android Rendering Problems :The following classes could not be instantiated
- 聚合测试数据
- Android 6.0 动态权限机制
- 一种可以避免数据迁移的分库分表scale-out扩容方式