本人 6年级 耗时0.2个月luoguP2493 [SDOI2011] 贪食蛇AC
接下来由我为大家讲解
首先有一个结论:
当前最强的蛇吃了最弱的蛇之后,如果没有变成最弱的蛇,他一定会选择吃!
证明:
假设当前最强的蛇叫石老板。
如果下一条最强的蛇如果依旧是石老板,那肯定不吃白不吃;
如果下一条最强蛇不是石老板,此时最强的蛇没有原先强,最弱的蛇也没原先弱,吃掉后肯定比石老板要弱。也就是说,当前最强的蛇吃了之后,如果会死,也会死在石老板前面。那么这样一来,这条蛇会想尽办法不死,从而石老板也一定能不死。
有了这个结论,一部分蛇可以放心大胆地吃了,但是问题来了,如果吃了之后变成最弱的蛇了,到底选择吃不吃呢?
稍微往后推一推就明白了:
当前最强蛇记为石老板,下一条最强蛇记为喵老板。石老板进食后变成最弱的蛇了,如果喵老板进食后不是最弱的蛇,他就会选择吃(根据开头的结论),这样石老板就凉了,所以石老板当初的选择一定是不吃。
如果喵老板进食后依旧是最弱的蛇,那就会考虑下一条最强蛇的情况,起名为汪老板。同样分两种情况:如果汪老板进食后不是最弱的蛇,那他就会选择吃,这样喵老板就凉了,所以他当初会选择不吃,这样石老板就不会死,那么石老板当初就会选择吃。如果汪老板进食后变成了最弱的蛇,那就再考虑下一条蛇………………
这个问题就变成了一个递归的问题了,直到某条蛇吃了之后不是最弱的蛇或者只能下两条蛇为止。这样,最后一条蛇会选择吃,倒数第二条蛇为了保命会选择不吃,倒数第三条蛇可以放心大胆的吃,倒数第四条蛇会保命选择不吃,倒数第五条蛇可以放心吃………………
这样,石老板选择吃不吃,就和最后一条蛇之间的奇偶性相关了。并且石老板选择不吃,游戏结束,石老板选择吃,游戏也会在下一轮结束(因为喵老板会选择不吃)。
到目前为止,这个题目很清晰了,只需模拟两个阶段即可:
阶段一:所有最强蛇进食后都不是最弱蛇,放心大胆吃!
阶段二:所有最强蛇进食后都是最弱蛇,直到有条蛇可以放心吃为止(吃了后不是最弱或者只剩两条)
阶段一结束时,游戏就基本结束了(根据阶段二的奇偶性看能不能再吃一次)
接下来送出AC代码 代码为C++14 运行
感谢大家的收看
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
const int maxr=17,maxc=17,maxq=15*15*1440*16*8,maxS=1<<11;
const int dx[]={0,0,-1,1};
const int dy[]={-1,1,0,0};
const char Dir[]={'L','R','U','D'};
int snakePos0[4][2];
int map[maxr][maxc],foodMap[maxr][maxc];
int stat[maxS][4],foodStat[maxS][4];
int q[maxq],pred[maxq];
unsigned char visit[1<<23];
char path[1000];
int ansTime,ansLink,foodCnt,pathLength,r,c;
int expand(int stat,int len,int k){
int tmp=stat;
len+=4;
k^=1;
int x=dx[k],y=dy[k];
for(int i=2;i<len;++i){
x+=dx[tmp&3];
y+=dy[tmp&3];
tmp>>=2;
if(!x && !y) return -1;
}
return (stat<<2 & ((1<<(len+len-2))-1)) | k;
}
void calcStat(){
//calculate the state of snake when it moves.
memset(stat,0xff,sizeof stat);
memset(foodStat,0xff,sizeof foodStat);
int head=0,tail=1;
int visit[1<<14]={0};
for(int i=3;i>0;--i){
int k=0;
while(snakePos0[i-1][0]+dx[k]!=snakePos0[i][0]||snakePos0[i-1][1]+dy[k]!=snakePos0[i][1])
++k;
q[1]=q[1]<<2|k;
}
q[1]<<=2;//头部没有“方向“,这两位是存储长度的。
visit[q[1]]=1;
while(head<tail){
int s0=q[++head];
int len0=s0&3;
int snakeStat0=s0>>2;
for(int k=0;k<4;++k){
int snakeStat1=expand(snakeStat0,len0,k);
if(snakeStat1>=0){
int s1=(snakeStat1 ) << 2 |len0;
if(!visit[s1]){
q[++tail]=s1;
visit[s1]=tail;
}
stat[head][k]=visit[s1];
}
}
//grow
for(int k=0;k<4;++k){
int snakeStat1=expand(snakeStat0,len0+1,k);
if(snakeStat1>=0){
if(len0<3){
int s1=(snakeStat1 ) << 2 |(len0+1);
if(!visit[s1]){//好像0xfff不加也行。。。
q[++tail]=s1;
visit[s1]=tail;
}
foodStat[head][k]=visit[s1];
}
else{
foodStat[head][k]=0;
//到达长度8,即到达目标状态
}
}
}
}
// printf("%d %d",head,tail);//tail=1200!!!
}
#define mkStat(x,y,ss,fs,wt) (((x)<<22)|((y)<<18)|((ss)<<7)|((fs)<<3)|(wt))
void bfs(){//这里的 ss是上面calcStat中队列的下标
// memset(q,0,sizeof q);
// memset(visit,0,sizeof visit);
int head=0,tail=1;
q[1]=mkStat(snakePos0[0][0],snakePos0[0][1],1,(1<<foodCnt)-1,0);
visit[q[1]>>3]|=1<<0;
while(head<tail){
int s0=q[++head];
int x0 = s0 >> 22 & 0xf,
y0 = s0 >> 18 & 0xf,
snakeStat0 = s0 >> 7 & 0x7ff,
foodStat0 = s0 >> 3 & 0xf,
waitTime0 = s0 & 7;
if(!foodStat0 && !waitTime0){
ansLink=head;
// printf("Anslink=%d\n",ansLink);
break;
}
if(waitTime0){
int s1=mkStat(x0,y0,snakeStat0,foodStat0,waitTime0-1);
if(!(visit[s1>>3] & 1<<(waitTime0-1))){
visit[s1>>3]|=1<<(waitTime0-1);
q[++tail]=s1;
pred[tail]=head;
}
}
else{
for(int k=0;k<4;++k){
int x1=x0+dx[k],
y1=y0+dy[k],
snakeStat1=stat[snakeStat0][k],
foodStat1=foodStat0,
waitTime1=abs(map[x1][y1]-map[x0][y0]);
if(!map[x1][y1]) continue;
if(foodMap[x1][y1]&&(foodStat1& 1<< (foodMap[x1][y1]-1))){
foodStat1^=1<<(foodMap[x1][y1]-1);
snakeStat1=foodStat[snakeStat0][k];
}
else snakeStat1=stat[snakeStat0][k];
if(snakeStat1>=0){
int s1=mkStat(x1,y1,snakeStat1,foodStat1,waitTime1);
if(!(visit[s1>>3] & 1<< waitTime1)){//不要减一!!不要减一!!
visit[s1>>3]|=1<< waitTime1;
q[++tail]=s1;
pred[tail]=head;
}
}
}
}
}
// printf("%d\n",tail);
}
inline void input(){
scanf("%d%d",&r,&c);
char str[20];
for(int i=1;i<=r;++i){
scanf("%s",str);
for(int j=0;j<c;++j){
map[i][j+1]=str[j]-48;
}
}
for(int i=0;i<4;++i)
scanf("%d%d",&snakePos0[i][0],&snakePos0[i][1]);
int x,y;
scanf("%d",&foodCnt);
for(int i=1;i<=foodCnt;++i){
scanf("%d%d",&x,&y);
foodMap[x][y]=i;
}
}
inline void calcAns(){
bfs();
int p1=ansLink;
int x0,y0,x1,y1,wt;
x1=q[p1]>>22&0xf;
y1=q[p1]>>18&0xf;
while(p1>1){
int p0=pred[p1];
x0=q[p0]>>22 & 0xf;
y0=q[p0]>>18 & 0xf;
// wt=q[p0]&7;
ansTime++;
/* if(!wt){
int k=0;
while(x0+dx[k]!=x1||y0+dy[k]!=y1)
++k;
path[pathLength++]=Dir[k];
}
*/ x1=x0,y1=y0;
p1=p0;
}
// reverse(path,path+pathLength);
}
inline void output(){
if(!ansLink)
puts("No solution.");
else{
printf("%d\n",ansTime);
// for(int i=0;i<pathLength;++i)
// putchar(path[i]);
// putchar('\n');
}
}
int main(){
input();
calcStat();
calcAns();
output();
return 0;
}