hdu4121 象棋checkmate模拟
http://acm.hdu.edu.cn/showproblem.php?pid=4121
几百年前就做过这道题了,没想到坑到这个地步了。。。。。
很简单,就是判断一个黑先手的局面是否checkmate(黑必败局,红必胜终局)
随便秀一下写程序之前的草稿
/*1.黑先红后 2.黑无论,红有胜 3.两种棋子,帅马将 车炮帅 4.检查棋盘合法性 不跃出棋盘 5.独立合法 范围 路径 终点 数组走法路径: 帅将有范围 马的不蹩脚 红的终点不红 飞行路径: 四方扫 红的终点不同红 帅车遇到红-1/+1或者黑为界限 炮隔一个两个为界限 帅同列吃 6.eat检测 有无将 7.一个棋子遗留局面vector int blockcnt 统计某一个方向有多少个棋子阻碍着 int check(红的不红,帅范围) vec go() int solve() { for 黑子 for红子 }*/
ac代码
#include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<string> #include<cctype> #include<stack> #include<queue> #include<set> #include<sstream> #include<map> #include<ctime> using namespace std; #define For(i,k,n) for(int i=k;i<=n;i++) #define ForD(i,k,n) for(int i=n;i>=k;i--) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define NEG(a) memset(a,-1,sizeof(a)); #define FILL(a) memset(a,0x3f,sizeof(a)); #define INF 0x3f3f3f3f #define LLINF 0x3f3f3f3f3f3f3f3f #define ll long long #define print(b,a) cout<<b<<"="<<a<<endl; #define printbin(b,a){int tmp=a;string s;do{s+=tmp%2+'0';tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;} #define printarr(i,a,f,b) {For(i,f,b) printf("%d ",a[i]); printf("\n");} #define bg -1 #define rg 1 #define cr 2 #define cn 3 #define hr 4 struct node { int t[11][10]; }; int check(node nd,int r,int c,int nr,int nc) { if(nd.t[r][c]>0&&nd.t[nr][nc]>0) return 0; else if(nd.t[r][c]==rg&&(nr<=7||nr>=11||nc<=3||nc>=7)) return 0; else if(nd.t[r][c]==bg&&(nr<=0||nr>=4||nc<=3||nc>=7)) return 0; else if(nr<=0||nr>=11||nc<=0||nc>=10) return 0; else return 1; } int blockcnt(node nd,int r,int c,int l,int u,int flg) { if(l>u) swap(l,u); int d=0,cnt=0; if(flg==1) d=(nd.t[u][c]!=0)+(nd.t[l][c]!=0); if(flg==0) d=(nd.t[r][u]!=0)+(nd.t[r][l]!=0); //printf("flg=%d d=%d\n",flg,d); For(k,l,u) { if(flg==0) { if(nd.t[r][k]) { cnt++; } } else { if(nd.t[k][c]) { cnt++; } } } cnt-=d; //printf("r=%d c=%d l=%d u=%d cnt=%d\n",r,c,l,u,cnt); return cnt; } int alive(node nd) { int flg=0; For(i,1,10) { For(j,1,9) { if(nd.t[i][j]==bg) flg=1; } } return flg; } vector<node>go(node nd,int r,int c) //move i,j { int tp=nd.t[r][c]; vector<node>st; if(tp==bg||tp==rg) { int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; For(k,0,3) { int nr=r+d[k][0],nc=c+d[k][1]; //printf("nr=%d nc=%d\n",nr,nc); if(check(nd,r,c,nr,nc)) { node nnd=nd; nnd.t[r][c]=0; nnd.t[nr][nc]=tp; st.push_back(nnd); } } For(nr,1,10) { if(nr==r) continue; else { if(nd.t[nr][c]==-tp &&blockcnt(nd,r,c,r,nr,1)==0 ) { node nnd=nd; nnd.t[r][c]=0; nnd.t[nr][c]=tp; st.push_back(nnd); } } } } else if(tp==cr) { For(nr,1,10) { if(nr==r) continue; if(blockcnt(nd,r,c,r,nr,1)==0 &&check(nd,r,c,nr,c) ) { node nnd=nd; nnd.t[r][c]=0; nnd.t[nr][c]=tp; st.push_back(nnd); } } For(nc,1,9) { if(nc==c) continue; if(blockcnt(nd,r,c,c,nc,0)==0 &&check(nd,r,c,r,nc) ) { node nnd=nd; nnd.t[r][c]=0; nnd.t[r][nc]=tp; st.push_back(nnd); } } } else if(tp==cn) { For(nr,1,10) { if(nr==r) continue; if(((nd.t[nr][c]&&blockcnt(nd,r,c,r,nr,1)==1) ||(!nd.t[nr][c]&&blockcnt(nd,r,c,r,nr,1)==0)) &&check(nd,r,c,nr,c) ) { node nnd=nd; nnd.t[r][c]=0; nnd.t[nr][c]=tp; st.push_back(nnd); } } For(nc,1,9) { if(nc==c) continue; if(((nd.t[r][nc]&&blockcnt(nd,r,c,c,nc,0)==1) ||(!nd.t[r][nc]&&blockcnt(nd,r,c,c,nc,0)==0)) &&check(nd,r,c,r,nc) ) { node nnd=nd; nnd.t[r][c]=0; nnd.t[r][nc]=tp; st.push_back(nnd); } } } else { int d[8][2]={{2,1},{2,-1},{-2,1},{-2,-1} ,{1,2},{1,-2},{-1,2},{-1,-2} }; For(k,0,7) { int nr=r+d[k][0],nc=c+d[k][1]; if(abs(d[k][0])==2) { int nnr=nr-d[k][0]/2; if(nd.t[nnr][c]) continue; } else { int nnc=nc-d[k][1]/2; if(nd.t[r][nnc]) continue; } if(check(nd,r,c,nr,nc)) { node nnd=nd; nnd.t[r][c]=0; nnd.t[nr][nc]=tp; st.push_back(nnd); } } } //printf("sz=%d\n",st.size()); return st; } int solve(node nd) { int checkmate=1; For(i,1,10) { For(j,1,9) { if(nd.t[i][j]>=0) continue; vector<node>st=go(nd,i,j); int sz=st.size(); For(k,0,sz-1) { node _nd=st[k]; //printf("father:\n"); //For(r,1,10) //printarr(c,st[k].t[r],1,9); int canwin=0; For(_i,1,10) { For(_j,1,9) { if(nd.t[_i][_j]<=0) continue; vector<node>_st=go(_nd,_i,_j); int _sz=_st.size(); For(_k,0,_sz-1) { //printf("%d %d son:\n",_i,_j); //For(_r,1,10) //printarr(_c,_st[_k].t[_r],1,9); if(!alive(_st[_k])) canwin=1; } } } if(!canwin) checkmate=0; } } } return checkmate; } int main() { //freopen("in.txt","r",stdin); int N,R,C; while(cin>>N>>R>>C&&!(N==0&&R==0&&C==0)){ node init; MEM(init.t); init.t[R][C]=bg; For(i,1,N) { char cc; cin>>cc>>R>>C; int tp; if(cc=='G') tp=rg; else if(cc=='R') tp=cr; else if(cc=='C') tp=cn; else tp=hr; init.t[R][C]=tp; } if(solve(init)) puts("YES"); else puts("NO"); } return 0; }
思路:
go函数返回当前局面可以的下一步局面的集合,check函数专门检查范围性的合法性,棋子特殊合法性由go解决,而棋子合法性中例如炮车需要的监测障碍由blockcnt解决,最后solve针对局面集合判断checkmate。
错误:
但是错误依然很多,于是采用了两两棋子构造简单数据,打印局面,检测各个棋子走法正确性的方法。
犯的错误包括忘记了象棋不吃子和车走法一样,没有考虑棋子不能不走,变量混淆,blockcnt没有考虑我把上下界调整了的情况等等。。。
启示:
启示就是模拟类的:1.打草稿 2.单元测试 3.变量厘清 4.功能分割,要写针对数据和状态的代码,不要写针对路径的代码。
喂 人脑是怎么这么快学会象棋的啊啊啊啊啊啊啊啊,我将个军都写得上气不接下气)