1. 程式人生 > >【Luogu】P3930 SAC E#1 - 一道大水題 Knight

【Luogu】P3930 SAC E#1 - 一道大水題 Knight

經營 scan closed char node pty pri b- 種類

【題目】洛谷10月月賽R1 提高組

【題意】給定n*n棋盤和<=16個棋子,給幾個棋子種類和攻擊範圍,現我方只有一馬,求能否吃王。

【算法】狀壓+BFS

【題解】16種棋子中,馬不能吃馬,直接處理馬和王,那麽就剩13個棋子,可以壓成2^13表示棋盤現有棋子存活狀態。

然後對vis[2^13][n][n]進行bfs。

細節:

1.攻擊直到碰到其它棋子,那個碰到的棋子也算攻擊範圍內。

2.判斷碰到棋子時,註意該棋子是否在當前局面存活。

3.多組數據,Q中途退出要清空。

學到了:

1.一份長代碼要細心經營,視若珍寶,動鍵盤之前要冷靜把思路和框架理清楚,過程中步步為營,慢慢寫總能寫完的。

2.不要輕易相信自己的代碼沒有bug了,盡量對拍,把小數據的中間結果輸出和手算比較正確性,從而改掉盡可能多的錯誤。

3.不要害怕寫長的復雜的代碼,先做框架,然後一步一步把子過程做好,一份超長代碼就慢慢構造出來了。

4.枚舉對角線的姿勢!

技術分享
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f,maxn=60;
int n,mp[1<<14][maxn][maxn],map[maxn][maxn],p[maxn][maxn],ans;
int cnt,tot,Tx,Ty,Sx,Sy; bool vis[1<<14][maxn][maxn]; struct Node{int x,y;}c[15],ch[15]; struct cyc{int S,x,y,st;}; queue<cyc>Q; void qishi(int S,int x,int y){ mp[S][x-1][y+2]=mp[S][x+1][y+2]=mp[S][x+2][y-1]=mp[S][x+2][y+1]=1; if(x-2>0)mp[S][x-2][y-1]=mp[S][x-2][y+1]=1; if(y-2
>0)mp[S][x-1][y-2]=mp[S][x+1][y-2]=1; } void king(int S,int x,int y){ mp[S][x-1][y-1]=mp[S][x-1][y]=mp[S][x-1][y+1]=1; mp[S][x][y-1]=mp[S][x][y+1]=1; mp[S][x+1][y-1]=mp[S][x+1][y]=mp[S][x+1][y+1]=1; } bool m(int S,int x,int y){ if(map[x][y]<=1)return 1; if(map[x][y]==2||map[x][y]==7)return 0; if(S&(1<<(p[x][y]-1)))return 0; return 1; } void chengbao(int S,int x,int y){ for(int i=x-1;i>=1;i--)if(m(S,i,y))mp[S][i][y]=1;else{mp[S][i][y]=1;break;} for(int i=x+1;i<=n;i++)if(m(S,i,y))mp[S][i][y]=1;else{mp[S][i][y]=1;break;} for(int i=y-1;i>=1;i--)if(m(S,x,i))mp[S][x][i]=1;else{mp[S][x][i]=1;break;} for(int i=y+1;i<=n;i++)if(m(S,x,i))mp[S][x][i]=1;else{mp[S][x][i]=1;break;} } void zhujiao(int S,int x,int y){ for(int i=1;i<min(x,y);i++)if(m(S,x-i,y-i))mp[S][x-i][y-i]=1;else{mp[S][x-i][y-i]=1;break;} for(int i=1;i<=min(n-x,n-y);i++)if(m(S,x+i,y+i))mp[S][x+i][y+i]=1;else{mp[S][x+i][y+i]=1;break;} for(int i=1;i<=min(x,n-y);i++)if(m(S,x-i,y+i))mp[S][x-i][y+i]=1;else{mp[S][x-i][y+i]=1;break;} for(int i=1;i<=min(n-x,y);i++)if(m(S,x+i,y-i))mp[S][x+i][y-i]=1;else{mp[S][x+i][y-i]=1;break;} } void soldier(int S,int x,int y){ mp[S][x+1][y-1]=mp[S][x+1][y+1]=1; } void check(int S,int x,int y,int st){ if(x<1||x>n||y<1||y>n||mp[S][x][y]||vis[S][x][y])return; vis[S][x][y]=1; if(map[x][y]==2)ans=st; if(map[x][y]>=3&&map[x][y]<=6)if(S&(1<<(p[x][y]-1)))S^=(1<<(p[x][y]-1)); vis[S][x][y]=1; Q.push((cyc){S,x,y,st}); } char s[maxn]; int main(){ while(scanf("%d",&n)==1){ cnt=tot=0; memset(map,0,sizeof(map));memset(p,0,sizeof(p));memset(mp,0,sizeof(mp));memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=n;j++){ if(s[j]==K)map[i][j]=7,c[++cnt].x=i,c[cnt].y=j; if(s[j]==X)map[i][j]=2,Tx=i,Ty=j,c[++cnt].x=i,c[cnt].y=j; if(s[j]==O)Sx=i,Sy=j; if(s[j]==C)map[i][j]=3,ch[tot].x=i,ch[tot].y=j,p[i][j]=tot++; if(s[j]==B)map[i][j]=4,ch[tot].x=i,ch[tot].y=j,p[i][j]=tot++; if(s[j]==Q)map[i][j]=5,ch[tot].x=i,ch[tot].y=j,p[i][j]=tot++; if(s[j]==P)map[i][j]=6,ch[tot].x=i,ch[tot].y=j,p[i][j]=tot++; } } for(int S=0;S<(1<<tot);S++){ for(int i=1;i<=cnt;i++)if(map[c[i].x][c[i].y]==7)qishi(S,c[i].x,c[i].y);else king(S,c[i].x,c[i].y); for(int i=0;i<tot;i++)if((1<<i)&S){ int x=ch[i].x,y=ch[i].y; if(map[x][y]==3)chengbao(S,x,y); if(map[x][y]==4)zhujiao(S,x,y); if(map[x][y]==5)chengbao(S,x,y),zhujiao(S,x,y); if(map[x][y]==6)soldier(S,x,y); } mp[S][Tx][Ty]=0; } if(mp[(1<<tot)-1][Sx][Sy]==1){printf("-1\n");continue;} while(!Q.empty())Q.pop(); Q.push((cyc){(1<<tot)-1,Sx,Sy,0});vis[(1<<tot)-1][Sx][Sy]=1; ans=0; while(!Q.empty()){ cyc q=Q.front();Q.pop(); check(q.S,q.x-2,q.y-1,q.st+1);check(q.S,q.x-2,q.y+1,q.st+1); check(q.S,q.x-1,q.y-2,q.st+1);check(q.S,q.x-1,q.y+2,q.st+1); check(q.S,q.x+1,q.y-2,q.st+1);check(q.S,q.x+1,q.y+2,q.st+1); check(q.S,q.x+2,q.y-1,q.st+1);check(q.S,q.x+2,q.y+1,q.st+1); if(ans)break; } if(ans==0)printf("-1\n");else printf("%d\n",ans); } return 0; }
View Code

【Luogu】P3930 SAC E#1 - 一道大水題 Knight