• [SDOI2010]猪国杀题解


    题目链接:

    洛谷P2482

    loj2885

    bzoj1972

    推荐去loj看题,可以下数据因为特别容易出错

    sol

    其实这题码量也没那大,格式化后我的代码只有141行,在loj目前最短。最好多些一些函数,给每个猪开一个结构体。

    游戏结束、一些数组/变量

    之所以一开始就写结束,是因为以后要用。

    void end() {
    	puts(a[1].xue?"MP":"FP");//判断输赢
    	for(int i=1; i<=n; i++) {//输出每只猪的状态
    		if(a[i].xue==0)puts("DEAD");
    		else {
    			for(int j=0; j<a[i].s-1; j++)
    				printf("%c ",a[i].pai[j]);
    			if(a[i].s)printf("%c",a[i].pai[a[i].s-1]);
    			puts("");
    		}
    	}
    	exit(0);//退出整个程序
    }
    

    数组/变量

    int nxt[15],las[15],top,f,n,m;
    //nxt,las为链表,后会解释,top为牌堆顶,f为反猪数量,n为总猪数,m为总牌数
    char tem[5],paidui[2010];//tem用来输入,paidui就是牌堆
    

    每个猪的结构体:

    struct pig {
    	char tp,pai[2010];//tp:真实身份,M主猪,Z忠猪,F反猪,pai:手牌
    	int xue,s,z,t;
    	//xue:血量,s:牌数,z:是否有猪哥连弩(Z),t:表面身份,0:未知,1:忠猪,2:反猪,3:类反猪
    	void qizhi(int &x) {//将第x张牌弃置
    		s--;
    		for(int i=x; i<s; i++)
    			pai[i]=pai[i+1];
    		x--;
    	}
    	int seach(char ch) {//搜索第一张为ch的牌,有就弃置,返回1,否则返回0
    		for(int i=0; i<s; i++)
    			if(pai[i]==ch) {
    				qizhi(i);
    				return 1;
    			}
    		return 0;
    	}
    	void mopai(int x) {//从牌堆中摸x张牌
    		for(int i=1; i<=x; i++) {
    			pai[s++]=paidui[top++];
    			if(top==m)top--;
    		}
    	}
    } a[15];
    

    弃置我是暴力删,可以用vector<char>,然后摸牌有一个bug,牌不够用,要一直摸最后一张牌。

    献殷勤、表敌意、跳忠、跳反

    define两个语句

    #define dipig(x,y) ((a[x].tp=='M'&&(a[y].t==2||a[y].t==3))||(a[x].tp=='Z'&&a[y].t==2)||(a[x].tp=='F'&&a[y].t==1))
    \x能否对y表敌意
    #define youpig(x,y) (((a[x].tp=='M'||a[x].tp=='Z')&&a[y].t==1)||(a[x].tp=='F'&&a[y].t==2))
    \x能否对y献殷勤
    \y若未表明身份则都不能
    

    跳忠、跳反很简单,如果他使用了『杀(K)』,『决斗(F)』,『无懈可击(J)』,就表明了身份,那么忠猪跳忠,反猪跳反。这里我把主猪当成一种特殊的忠猪,一开始就跳忠。

    伤害、死亡

    由于猪会死亡,且他们坐成一圈,所以我用了链表。

    int nxt[15],las[15];//双向链表
    void killed(int g,int p) {//g杀死了p
    	if(a[p].tp=='M')end();//主猪死了,结束
    	if(a[p].tp=='F') {
    		if(!--f)end();//没有反猪了,结束
    		a[g].mopai(3);//摸三张奖励牌
    	} else if(a[p].tp=='Z'&&a[g].tp=='M')a[g].s=a[g].z=0;
    	//主猪杀了忠猪,弃置所以牌和装备
    	nxt[las[p]]=nxt[p];//从链表从删除p
    	las[nxt[p]]=las[p];
    }
    void kouxue(int x,int y) {//以x为伤害来源,攻击y
    	a[y].xue--;
    	if(!a[y].xue)a[y].xue+=a[y].seach('P');//濒死,可以吃一个桃
    	if(!a[y].xue)killed(x,y);//依然濒死,则y死亡
    }
    

    无懈可击

    这是一个特殊的牌,可能可以递归使用。

    int wxkj(int s,int x) {//无懈可击成功返回1,否则返回0
    	for(int i=s,f=0; !f||i!=s; i=nxt[i],f=1) {//从s开始
    		if((!x?(dipig(i,s)):(youpig(i,x)))&&a[i].seach('J')) {
    		//如果x不为0,说明s对x使用锦囊牌,否则说明s是上一次使用无懈可击
    		//根据题意判断是否使用无懈可击
    			a[i].t=a[i].tp=='F'?2:1;//i的身份明确
    			return !wxkj(i,0);//递归使用无懈可击
    		}
    	}
    	return 0;
    }
    

    主要操作

    终于到主要操作了~

    	int now=1;//now为当前回合的猪
    	a[1].t=1;//主猪一开始就跳忠
    	if(!f)end();//一开始就没反猪
    	while(1) {
    		int kill=0;//是否使用过杀
    		a[now].mopai(2);//摸2张牌
    		for(int i=0; i<a[now].s&&a[now].xue; i++) {//枚举每张牌
    			if(a[now].pai[i]=='Z') {//装备一定装备上,不管原来是否装备
    				a[now].z=1,a[now].qizhi(i);
    				i=-1;//可能之前杀可用,要从头枚举
    			} else if(a[now].pai[i]=='P'&&a[now].xue<4) {//有桃一定吃
    				a[now].xue++,a[now].qizhi(i);
    			} else if(a[now].pai[i]=='K'&&(a[now].z||!kill)) {//能用杀
    				int nx=nxt[now];//只能打下一个
    				if(dipig(now,nx)) {//能表敌意
    					a[now].t=a[now].tp=='F'?2:1;//now身份明确
    					a[now].qizhi(i);
    					kill=1;
    					if(!a[nx].seach('D'))kouxue(now,nx);//nx没闪就扣血
    				}
    			} else if(a[now].pai[i]=='F') {//有决斗一定用
    				for(int j=a[now].tp=='F'?1:nxt[now]; j!=now; j=nxt[j])
    				//反猪一定与主猪决斗
    					if(dipig(now,j)) {
    						a[now].qizhi(i);
    						a[now].t=a[now].tp=='F'?2:1;//now身份明确
    						if(wxkj(now,j))break;//使用无懈可击
    						if(a[j].tp=='Z'&&a[now].tp=='M') {
    							kouxue(now,j);//主猪与忠猪决斗忠猪直接扣血
    							break;
    						}
    						int t=1;
    						while(1) {//决斗
    							if(t==1) {
    								if(!a[j].seach('K')) {
    									kouxue(now,j);
    									break;
    								}
    							} else if(!a[now].seach('K')) {
    								kouxue(j,now),i=max(-1,i-1);
    								break;
    							}
    							t^=1;
    						}
    						i=-1;
    						//决斗可能会导致一些猪使用无懈可击,明确身份,要从头开始枚举牌
    						break;
    					}
    			} else if(a[now].pai[i]=='N'||a[now].pai[i]=='W') {
    				//有南猪入侵和万箭齐发一定用
    				char ch=a[now].pai[i];//保存是哪种
    				a[now].qizhi(i);
    				for(int j=nxt[now]; j!=now; j=nxt[j]) {//依次结算
    					if(!wxkj(now,j)&&!a[j].seach(ch=='N'?'K':'D')) {
    						if(a[j].tp=='M'&&!a[now].t)a[now].t=3;
    						//j是主猪,now未表明身份,则now为类反猪
    						kouxue(now,j);
    					}
    				}
    				i=-1;//同决斗,要从头开始枚举牌
    			}
    		}
    		now=nxt[now];
    	}
    

    完整代码

    注释就不打了

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    #define dipig(x,y) ((a[x].tp=='M'&&(a[y].t==2||a[y].t==3))||(a[x].tp=='Z'&&a[y].t==2)||(a[x].tp=='F'&&a[y].t==1))
    #define youpig(x,y) (((a[x].tp=='M'||a[x].tp=='Z')&&a[y].t==1)||(a[x].tp=='F'&&a[y].t==2))
    int nxt[15],las[15],top,f,n,m;
    char tem[5],paidui[2010];
    struct pig {
    	char tp,pai[2010];
    	int xue,s,z,t;
    	void qizhi(int &x) {
    		s--;
    		for(int i=x; i<s; i++)
    			pai[i]=pai[i+1];
    		x--;
    	}
    	int seach(char ch) {
    		for(int i=0; i<s; i++)
    			if(pai[i]==ch) {
    				qizhi(i);
    				return 1;
    			}
    		return 0;
    	}
    	void mopai(int x) {
    		for(int i=1; i<=x; i++) {
    			pai[s++]=paidui[top++];
    			if(top==m)top--;
    		}
    	}
    } a[15];
    void end() {
    	puts(a[1].xue?"MP":"FP");
    	for(int i=1; i<=n; i++) {
    		if(a[i].xue==0)puts("DEAD");
    		else {
    			for(int j=0; j<a[i].s-1; j++)
    				printf("%c ",a[i].pai[j]);
    			if(a[i].s)printf("%c",a[i].pai[a[i].s-1]);
    			puts("");
    		}
    	}
    	exit(0);
    }
    void killed(int g,int p) {
    	if(a[p].tp=='M')end();
    	if(a[p].tp=='F') {
    		if(!--f)end();
    		a[g].mopai(3);
    	} else if(a[p].tp=='Z'&&a[g].tp=='M')a[g].s=a[g].z=0;
    	nxt[las[p]]=nxt[p];
    	las[nxt[p]]=las[p];
    }
    void kouxue(int x,int y) {
    	a[y].xue--;
    	if(!a[y].xue)a[y].xue+=a[y].seach('P');
    	if(!a[y].xue)killed(x,y);
    }
    int wxkj(int s,int x) {
    	for(int i=s,f=0; !f||i!=s; i=nxt[i],f=1) {
    		if((!x?(dipig(i,s)):(youpig(i,x)))&&a[i].seach('J')) {
    			a[i].t=a[i].tp=='F'?2:1;
    			return !wxkj(i,0);
    		}
    	}
    	return 0;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i=1; i<=n; i++) {
    		scanf("%s",tem);
    		a[i].tp=tem[0];
    		f+=tem[0]=='F';
    		for(int j=0; j<4; j++)
    			cin>>a[i].pai[j];
    		nxt[i]=i+1,las[i]=i-1;
    		a[i].s=a[i].xue=4;
    	}
    	for(int i=0; i<m; i++)cin>>paidui[i];
    	nxt[n]=1,las[1]=n;
    	int now=1;
    	a[1].t=1;
    	if(!f)end();
    	while(1) {
    		int kill=0;
    		a[now].mopai(2);
    		for(int i=0; i<a[now].s&&a[now].xue; i++) {
    			if(a[now].pai[i]=='Z') {
    				a[now].z=1,a[now].qizhi(i);
    				i=-1;
    			} else if(a[now].pai[i]=='P'&&a[now].xue<4) {
    				a[now].xue++,a[now].qizhi(i);
    			} else if(a[now].pai[i]=='K'&&(a[now].z||!kill)) {
    				int nx=nxt[now];
    				if(dipig(now,nx)) {
    					a[now].t=a[now].tp=='F'?2:1;
    					a[now].qizhi(i);
    					kill=1;
    					if(!a[nx].seach('D'))kouxue(now,nx);
    				}
    			} else if(a[now].pai[i]=='F') {
    				for(int j=a[now].tp=='F'?1:nxt[now]; j!=now; j=nxt[j])
    					if(dipig(now,j)) {
    						a[now].qizhi(i);
    						a[now].t=a[now].tp=='F'?2:1;
    						if(wxkj(now,j))break;
    						if(a[j].tp=='Z'&&a[now].tp=='M') {
    							kouxue(now,j);
    							break;
    						}
    						int t=1;
    						while(1) {
    							if(t==1) {
    								if(!a[j].seach('K')) {
    									kouxue(now,j);
    									break;
    								}
    							} else if(!a[now].seach('K')) {
    								kouxue(j,now),i=max(-1,i-1);
    								break;
    							}
    							t^=1;
    						}
    						i=-1;
    						break;
    					}
    			} else if(a[now].pai[i]=='N'||a[now].pai[i]=='W') {
    				char ch=a[now].pai[i];
    				a[now].qizhi(i);
    				for(int j=nxt[now]; j!=now; j=nxt[j]) {
    					if(!wxkj(now,j)&&!a[j].seach(ch=='N'?'K':'D')) {
    						if(a[j].tp=='M'&&!a[now].t)a[now].t=3;
    						kouxue(now,j);
    					}
    				}
    				i=-1;
    			}
    		}
    		now=nxt[now];
    	}
    	return 0;
    }
    

    观战模式

    这个代码输出了每一步,每回合,有一个getchar

    #include<bits/stdc++.h>
    using namespace std;
    #define dipig(x,y) ((a[x].tp=='M'&&(a[y].t==2||a[y].t==3))||(a[x].tp=='Z'&&a[y].t==2)||(a[x].tp=='F'&&a[y].t==1))
    #define youpig(x,y) (((a[x].tp=='M'||a[x].tp=='Z')&&a[y].t==1)||(a[x].tp=='F'&&a[y].t==2))
    int nxt[15],las[15],top,f,n,m;
    char tem[5],paidui[2010];
    struct pig {
    	char tp,pai[2010];
    	int xue,s,z,t;
    	void qizhi(int &x) {
    		s--;
    		for(int i=x; i<s; i++)
    			pai[i]=pai[i+1];
    		x--;
    	}
    	int seach(char ch) {
    		for(int i=0; i<s; i++)
    			if(pai[i]==ch) {
    				qizhi(i);
    				return 1;
    			}
    		return 0;
    	}
    	void mopai(int x) {
    		for(int i=1; i<=x; i++) {
    			pai[s++]=paidui[top++];
    			if(top==m)top--;
    		}
    	}
    } a[15];
    void end() {
    	puts(a[1].xue?"MP":"FP");
    	for(int i=1; i<=n; i++) {
    		if(a[i].xue==0)puts("DEAD");
    		else {
    			for(int j=0; j<a[i].s-1; j++)
    				printf("%c ",a[i].pai[j]);
    			if(a[i].s)printf("%c",a[i].pai[a[i].s-1]);
    			puts("");
    		}
    	}
    	exit(0);
    }
    void killed(int g,int p) {
    	if(a[p].tp=='M')end();
    	if(a[p].tp=='F') {
    		if(!--f)end();
    		a[g].mopai(3);
    	} else if(a[p].tp=='Z'&&a[g].tp=='M')a[g].s=a[g].z=0;
    	nxt[las[p]]=nxt[p];
    	las[nxt[p]]=las[p];
    }
    void kouxue(int x,int y) {
    	a[y].xue--;
    	if(!a[y].xue)
    		if(a[y].seach('P'))a[y].xue++,cerr<<'P'<<' '<<y<<endl;
    	if(!a[y].xue)killed(x,y);
    }
    int wxkj(int s,int x) {
    	for(int i=s,f=0; !f||i!=s; i=nxt[i],f=1) {
    		if((!x?(dipig(i,s)):(youpig(i,x)))&&a[i].seach('J')) {
    			a[i].t=a[i].tp=='F'?2:1;
    			cerr<<'J'<<' '<<i<<endl;
    			return !wxkj(i,0);
    		}
    	}
    	return 0;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i=1; i<=n; i++) {
    		scanf("%s",tem);
    		a[i].tp=tem[0];
    		f+=tem[0]=='F';
    		for(int j=0; j<4; j++)
    			cin>>a[i].pai[j];
    		nxt[i]=i+1,las[i]=i-1;
    		a[i].s=a[i].xue=4;
    	}
    	for(int i=0; i<m; i++)cin>>paidui[i];
    	nxt[n]=1,las[1]=n;
    	int now=1;
    	a[1].t=1;
    	if(!f)end();
    	while(1) {
    		int kill=0;
    		a[now].mopai(2);
    		getchar();
    		cerr<<now<<' '<<a[now].xue<<' '<<a[now].t<<' '<<a[now].z<<endl;
    		for(int i=0; i<a[now].s; i++)cerr<<a[now].pai[i]<<' ';
    		cerr<<endl;
    		for(int i=0; i<a[now].s&&a[now].xue; i++) {
    			if(a[now].pai[i]=='Z') {
    				cerr<<'Z'<<endl;
    				a[now].z=1,a[now].qizhi(i);
    				i=-1;
    			} else if(a[now].pai[i]=='P'&&a[now].xue<4) {
    				cerr<<'P'<<endl;
    				a[now].xue++,a[now].qizhi(i);
    			} else if(a[now].pai[i]=='K'&&(a[now].z||!kill)) {
    				int nx=nxt[now];
    				if(dipig(now,nx)) {
    					cerr<<'K'<<' '<<nx<<endl;
    					a[now].t=a[now].tp=='F'?2:1;
    					a[now].qizhi(i);
    					kill=1;
    					if(!a[nx].seach('D'))kouxue(now,nx);
    					else cerr<<'D'<<endl;
    				}
    			} else if(a[now].pai[i]=='F') {
    				for(int j=a[now].tp=='F'?1:nxt[now]; j!=now; j=nxt[j])
    					if(dipig(now,j)) {
    						cerr<<'F'<<' '<<j<<endl;
    						a[now].qizhi(i);
    						a[now].t=a[now].tp=='F'?2:1;
    						if(wxkj(now,j))break;
    						if(a[j].tp=='Z'&&a[now].tp=='M') {
    							kouxue(now,j);
    							break;
    						}
    						int t=1;
    						while(1) {
    							if(t==1) {
    								if(!a[j].seach('K')) {
    									kouxue(now,j);
    									break;
    								} else cerr<<'K'<<endl;
    							} else if(!a[now].seach('K')) {
    								kouxue(j,now),i=max(-1,i-1);
    								break;
    							} else cerr<<'K'<<endl;
    							t^=1;
    						}
    						i=-1;
    						break;
    					}
    			} else if(a[now].pai[i]=='N'||a[now].pai[i]=='W') {
    				char ch=a[now].pai[i];
    				a[now].qizhi(i);
    				cerr<<ch<<endl;
    				for(int j=nxt[now]; j!=now; j=nxt[j]) {
    					if(wxkj(now,j))continue;
    					if(!a[j].seach(ch=='N'?'K':'D')) {
    						if(a[j].tp=='M'&&!a[now].t)a[now].t=3;
    						kouxue(now,j);
    					} else cerr<<(ch=='N'?'K':'D')<<endl;
    				}
    				i=-1;
    			}
    		}
    		now=nxt[now];
    	}
    	return 0;
    }
    
  • 相关阅读:
    Vasya and Endless Credits CodeForces
    Dreamoon and Strings CodeForces
    Online Meeting CodeForces
    数塔取数 基础dp
    1001 数组中和等于K的数对 1090 3个数和为0
    1091 线段的重叠
    51nod 最小周长
    走格子 51nod
    1289 大鱼吃小鱼
    POJ 1979 Red and Black
  • 原文地址:https://www.cnblogs.com/hht2005/p/11526075.html
Copyright © 2020-2023  润新知