GDOI2016模拟8.14扫雷游戏
2015-08-15 19:02
183 查看
题目
chnlich 入手了一个新的扫雷游戏。在这个游戏中,地图是一个N*M 的矩阵,矩阵的每一个点有一个数字或没有数字。若一个格子内有数字,它表示它周围⑨个格子内(它自己和与它有公共点的8 个格子)的地雷个数。每个格子内最多只能有1 颗地雷。
然而只有这些信息,我们不能马上得知哪些格子内有地雷。不过因为chnlich 过于⑨,他觉得只要知道地雷最少可能的颗数,就能够挖掉所有的雷。他希望你帮他写一个程序,解决这个问题。当然,程序运行速度太慢或者错误可不行,如果1s 之内chnlich 还没有得到他
想要的信息,chnlich 就会把你打成⑨。
这个我们可以搜索来做
加上一下优化:
1、最优化剪枝,就是答案比现在的雷数小就break
2、可行性剪枝:
a、通过先选取能被越多数字包含的地方来做,并且预处理出,后面被少数字包含的地方都放满还缺几个,来确定下界
b、通过每个数字周围还缺多少个雷,取最大值作为上界(指被相同数字包含的地方的个数上界)
3、由于我打戳了,加了个卡时,但其实前两个就够了
贴代码
chnlich 入手了一个新的扫雷游戏。在这个游戏中,地图是一个N*M 的矩阵,矩阵的每一个点有一个数字或没有数字。若一个格子内有数字,它表示它周围⑨个格子内(它自己和与它有公共点的8 个格子)的地雷个数。每个格子内最多只能有1 颗地雷。
然而只有这些信息,我们不能马上得知哪些格子内有地雷。不过因为chnlich 过于⑨,他觉得只要知道地雷最少可能的颗数,就能够挖掉所有的雷。他希望你帮他写一个程序,解决这个问题。当然,程序运行速度太慢或者错误可不行,如果1s 之内chnlich 还没有得到他
想要的信息,chnlich 就会把你打成⑨。
这个我们可以搜索来做
加上一下优化:
1、最优化剪枝,就是答案比现在的雷数小就break
2、可行性剪枝:
a、通过先选取能被越多数字包含的地方来做,并且预处理出,后面被少数字包含的地方都放满还缺几个,来确定下界
b、通过每个数字周围还缺多少个雷,取最大值作为上界(指被相同数字包含的地方的个数上界)
3、由于我打戳了,加了个卡时,但其实前两个就够了
贴代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define N 16 #define M 100000 using namespace std; int n,m,t,ans,sum,Time; char map ; int a ,help ,b[3],s[M],one[M],c[M],f[M] ; struct node{ int v ; }d; void init(){ for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf(" %c",&map[i][j]); } void ins(int x,int y){ static int xx,yy,z; z=0; for (int i=0;i<3;i++){ xx=b[i]+x; if (xx&&xx<=n) for (int j=0;j<3;j++){ yy=b[j]+y; if (yy&&yy<=m) if (a[xx][yy]!=-1) z+=help[a[xx][yy]]; } } s[z]++; } bool cmp(int x,int y){ return one[x]>one[y]; } void dfs(int x,int y){ static bool p; int l,r; if (!(--Time))return; p=1; if (ans<=y)return; l=0; for (int i=0;i<sum;i++) l=max(l,d.v[i]); if (l+y>=ans)return; for (int i=0;i<sum;i++) if (d.v[i]){ p=0; break; } if (p){ ans=y; return; } l=0; r=s[c[x]]; for (int i=0;i<sum;i++) if (c[x]&help[i]) l=max(l,d.v[i]-f[x+1][i]),r=min(r,d.v[i]); for (int i=r;i>=l;i--){ for (int j=0;j<sum;j++) if (c[x]&help[j]) d.v[j]-=i; dfs(x+1,y+i); if (!Time)return; for (int j=0;j<sum;j++) if (c[x]&help[j]) d.v[j]+=i; } } void pre(){ ans=0; sum=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){ a[i][j]=-1; if (map[i][j]!='*'&&map[i][j]!='.') ans+=(d.v[sum]=map[i][j]-'0'),a[i][j]=sum++; } for (int i=0;i<help[sum];i++)s[i]=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (map[i][j]!='.') ins(i,j); for (int i=1;i<help[sum];i++) c[i]=i; sort(c+1,c+help[sum],cmp); c[0]=0; for (int i=1;i<help[sum];i++) if (s[c[i]])c[++c[0]]=c[i]; for (int i=0;i<sum;i++) f[c[0]+1][i]=0; for (int i=c[0];i;i--) for (int j=0;j<sum;j++) if (c[i]&help[j]) f[i][j]=min(f[i+1][j]+s[c[i]],d.v[j]); else f[i][j]=f[i+1][j]; } void work(){ dfs(1,0); } void predfs(int x,int y,int z){ one[x]=z++; for (int i=y;i<N;i++) predfs(x+help[i],i+1,z); } int main(){ scanf("%d %d",&n,&m); b[0]=-1,b[2]=1; help[0]=1; for (int i=1;i<N;i++) help[i]=help[i-1]+help[i-1]; predfs(0,0,0); while (n||m){ init(); pre(); if (ans!=45)Time=30000; else Time=4800000; work(); printf("%d\n",ans); scanf("%d %d",&n,&m); } return 0; }
相关文章推荐
- Nginx反向代理
- Linux文件目录权限总结
- STL顺序容器总结
- 存储过程2
- 点歌系统Simple版
- ZOJ 2588--Burning Bridges【无向图边双联通 && 输出桥的编号】
- Android环境结构--安装Eclipse错
- BZOJ 1053 [HAOI2007]反素数ant
- 对AsyncTask进行封装,简化繁琐的异步操作
- Eclipse 4.2 安装Java反编译插件
- Ubuntu之root权限的获取
- Eclipse 4.2 安装Java反编译插件
- 关于时间管理的一些技巧
- Code Forces 567B Berland National Library
- Android之AsyncTask源码解析
- socket可读/可写
- 我们为什么需要版本控制系统?
- apk 打包方式
- linux mkdir创建多层目录
- HDU 2137 circumgyrate the string