您的位置:首页 > 其它

GDOI2016模拟8.14扫雷游戏

2015-08-15 19:02 183 查看
题目

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: