这道题就是大模拟,没有任何方法可言,大约行左右的代码。一定要耐心,不断找出程序中的小,然后才能解决。数据可以从下载。
前面的题解已经把很多东西说得很明白了,我就来说一说我掉过的一些坑吧。
xxxxxxxxxx1.决斗可以对任何猪释放,不需要相邻,反猪必定对主猪释放,其他猪对后面一只与它敌对的猪释放。2.无懈可击可以循环释放,最好用递归实现。3.要实时更新每只猪的显现身份和存活情况,遇到游戏结束及时返回。4.除了桃以外,其他所有的牌释放后都必须从第一张开始重新模拟,因为前面的牌可能又能够使用了。5.牌堆没有牌时,要不断最后一张牌。
下面是程序分段讲解:
关于每只猪的定义
xxxxxxxxxxstruct player{int id;//真实身份int hp;//生命int cnt;//牌数char card[M];//牌int pre;//前面的那只猪int nxt;//后面的那只猪int pigid;//暴露身份bool special;//是否为类反猪bool weapon;//是否装备武器}pig[N];
多用用小函数,可以使程序变得更加简洁,从而不至于达到行的恐怖水平。
大家可能会把它写进主程序,因为它只会用到一次,但是在调试中这段语句可以帮你大忙。
xxxxxxxxxxvoid printcard(int i){bool first=true;for (int j=1;j<=pig[i].cnt;++j){if (pig[i].card[j]=='X') continue;if (!first){printf(" ");}else first=false;printf("%c",pig[i].card[j]);}printf("\n");}
找到卡牌就返回并扣除,没找到就返回。
xxxxxxxxxxint findcard(int x,char card){//x代表是哪头猪,card表示卡牌符号for (int i=1;i<=pig[x].cnt;++i){if (pig[x].card[i]==card){pig[x].card[i]='X';return true;}}return false;}
这个如果不写到过程里去的话,那我很佩服你的意志。
xxxxxxxxxxvoid getcard(int i){if (top>m) top=m;//牌堆没牌了,就不断摸最上面一张pig[i].cnt++;pig[i].card[pig[i].cnt]=cards[top];top++;//top表示牌堆的顶部}
这一次,我们把扣血和死亡结算放在一块运行。
我们考虑一头猪死了,如何更新整个环(链表?)继续运行下去,这就是我为什么要开设和了,一个前导和后继可以解决所有问题。
它前面的猪指向它后面的猪
它后面的猪指向它前面的猪
事实上,如果用暴力求解的话,也不会超时。
xxxxxxxxxxvoid dechp(int x,int i){//x是伤害来源者,i是伤害承受者pig[i].hp--;//扣血while (pig[i].hp<=0 && findcard(i,'P')){pig[i].hp++;//如果有桃赶快用}if (pig[i].hp<=0){//如果血还是没到0就回天乏术了pig[i].cnt=0;pig[i].weapon=false;//清空这个人的资料if (pig[i].id==1){gameover=true;//主猪死了游戏立刻结束return;}else if (pig[i].id==2){if (pig[x].id==1){//主猪杀了忠猪,按题目要求清空主猪的手牌pig[x].cnt=0;pig[x].weapon=false;//别忘了清空武器}}else if (pig[i].id==3){FPcnt--;//反猪的数量减1if (FPcnt==0){//如果已经没有反猪的话gameover=true;//游戏结束return;}getcard(x);getcard(x);getcard(x);//摸牌,记得千万不要放在上面的if语句前面}pig[pig[i].pre].nxt=pig[i].nxt;//更新前驱后继pig[pig[i].nxt].pre=pig[i].pre;}}
下面函数中,第一个表示询问和是不是敌人,第二个则询问两人是不是同伙,第三个表示向献殷勤,第四个表示向表敌意。
询问或变更的时候要以出发,应当判断的真实身份和的显露身份。没有显露身份则不能进行下去。
xxxxxxxxxxbool enemy(int x,int y){if (pig[x].id==1 && pig[y].special==true) return true;//对主猪而言,类反猪是敌人if (pig[y].pigid==0) return false;//y没有显露身份,返回falseif (pig[x].id!=3 && pig[y].pigid==3) return true;//对其他猪而言,身份不符的是敌人if (pig[x].id==3 && pig[y].pigid!=3) return true;return false;}bool friendly(int x,int y){//同理if (pig[y].pigid==0) return false;if (pig[x].id!=3 && pig[y].pigid!=3) return true;if (pig[x].id==3 && pig[y].pigid==3) return true;return false;}void getfriend(int x,int y){if (pig[y].pigid==0) return;//如果y没有显露身份,交朋友没有意义if (pig[y].pigid!=3) pig[x].special=false,pig[x].pigid=1;//否则就显露和y相同的身份,记得处理类反猪的头衔。if (pig[y].pigid==3) pig[x].special=true,pig[x].pigid=3;}void getenemy(int x,int y){//同理if (pig[y].pigid==0) return;if (pig[y].pigid!=3) pig[x].pigid=3,pig[x].special=true;if (pig[y].pigid==3) pig[x].pigid=1,pig[x].special=false;}
这里的部分卡牌,包括:
万箭齐发,决斗,南猪入侵,杀(闪),无懈可击
相对于其他几部分,这一部分相对容易些。
xxxxxxxxxxvoid usecard_k(int from,int to){getenemy(from,to);//这是一种表敌意的行为bool p=findcard(to,'D');//尝试去目标的牌库寻找闪if (p==false){dechp(from,to);//找不到,就扣血}}
决斗被无懈可击挡住的情况我们在这里暂不讨论,这里讨论的是如果对的决斗生效的情况。
xxxxxxxxxxvoid usecard_f(int from,int to){if (pig[from].id==1 && pig[to].id==2){//如果是主猪对忠猪下的手,忠猪不会还手dechp(from,to);return;}while (true){bool flag1=findcard(to,'K');//轮流在两人的牌库里寻找杀,找不到就扣血,退出。if (!flag1){dechp(from,to);return;}bool flag2=findcard(from,'K');if (!flag2){dechp(to,from);//如果自己出的牌害了自己,则需要把两人的攻击关系反一下return;}}}
这两个可以放在一起讨论。
xxxxxxxxxxvoid usecard_n(int from,int to){//南猪入侵while (true){if (gameover) return;//永远要注意实时更新游戏是否结束if (!usecard_j(from,to,0)){//如果没有被无懈可击挡住的话bool flag=findcard(to,'K');//在牌库中寻找杀if (!flag){if (pig[to].id==1 && pig[from].pigid==0){pig[from].special=true;//如果是忠猪误伤了主猪,且忠猪还未表露身份,则视为类反猪}dechp(from,to);//扣血}}to=pig[to].nxt;if (to==from) return;//一圈轮完,就退出}}void usecard_w(int from,int to){//万箭齐发while (true){if (gameover) return;if (!usecard_j(from,to,0)){bool flag=findcard(to,'D');//把这里改成D就可以了if (!flag){if (pig[to].id==1 && pig[from].pigid==0){pig[from].special=true;}dechp(from,to);}}to=pig[to].nxt;if (to==from) return;}}
这里就显得比较复杂了。我们用表示锦囊牌的发出者,表示锦囊牌的承受者,表示上一个无懈可击的发出者。初始为。
xxxxxxxxxxbool usecard_j(int from,int to,int last){int now=from;//轮流开始出无懈可击while (true){if ((last==0 && friendly(now,to)) || (last!=0 && enemy(now,last))){//如果你和锦囊牌的承受者是朋友或者和上一张无懈可击的发出者是敌人,那么就是用无懈可击。last的值确定了是哪种情况if (findcard(now,'J')){//如果有无懈可击可以出if (last==0 && friendly(now,to)) getfriend(now,to);if (last!=0 && enemy(now,last)) getenemy(now,last);//朋友和敌人关系更新,因为这是献殷勤和表敌意行为if (!usecard_j(pig[now].nxt,to,now)){return true;//如果没有被其他无懈可击抵消,那么这张无懈可击就是有效的}}}now=pig[now].nxt;if (now==from) return false;//绕完一圈就退出}}
嗯,没错,我们先讲这个,最后再来讲如何运行整个游戏。
xxxxxxxxxxint main(){scanf("%d%d",&n,&m);for (int i=1;i<N;++i){for (int j=1;j<M;++j){pig[i].card[j]='X';//X表示这个位置是空位}pig[i].hp=4;//初始生命为4}for (int i=1;i<=n;++i){char names[5],s[5];scanf("%s",names);for (int j=1;j<=4;++j){scanf("%s",s);pig[i].card[j]=s[0];//依次读入4张牌}pig[i].cnt=4;if (names[0]=='M') pig[i].id=1,pig[i].pigid=1;//主猪的身份一开始就暴露的else if (names[0]=='Z') pig[i].id=2;else pig[i].id=3,FPcnt++;//反猪,计数器加一pig[i].nxt=i+1;//前驱后继的初始化pig[i].pre=i-1;}pig[n].nxt=1;//特殊的前驱后继,构成整个环pig[1].pre=n;for (int i=1;i<=m;++i){char s[5];scanf("%s",s);cards[i]=s[0];//读入牌库的牌}top=1;//指针指向牌库的第一张牌rungame();//运行游戏(在下一部分)if (pig[1].hp<=0) printf("FP\n");else printf("MP\n");//获胜者输出for (int i=1;i<=n;++i){//依次输出每个人的牌if (pig[i].hp<=0) printf("DEAD\n");else{printcard(i);}}return 0;}
由于所有部分都已经讲完了,所以直接上代码。
xxxxxxxxxxvoid rungame(){while (true){//游戏一直运行下去for (int i=1;i<=n;++i){if (gameover) return;//实时准备游戏结束if (pig[i].hp<=0) continue;//猪死了就直接跳过getcard(i);getcard(i);//摸牌bool use_k=true;//表示这头猪是否出过杀for (int j=1;j<=pig[i].cnt;++j){if (pig[i].card[j]=='X') continue;//空牌,直接跳过if (gameover) return;switch (pig[i].card[j]){case 'P':{if (pig[i].hp<4){//如果能吃桃就吃pig[i].card[j]='X';pig[i].hp++;}break;}case 'K':{if (use_k && enemy(i,pig[i].nxt)){//如果和后面的一只猪是敌人pig[i].card[j]='X';usecard_k(i,pig[i].nxt);//直接上if (!pig[i].weapon){use_k=false;//没有连弩的话就不能再出杀了}j=0;//从头再来,因为整个场面可能发生改变}break;}case 'F':{//决斗,相对来说难实现一些if (pig[i].id==3){//如果是反猪,目标就是主猪pig[i].card[j]='X';getenemy(i,1);//和主猪表敌意if (usecard_j(i,1,0)) break;//如果被无懈可击挡住的话就退出usecard_f(i,1);j=0;}else{int to=pig[i].nxt;//还是逆时针循环找最近的敌对的猪while (true){if (enemy(i,to)){pig[i].card[j]='X';getenemy(i,to);if (usecard_j(i,to,0)) break;usecard_f(i,to);j=0;break;}to=pig[to].nxt;if (to==i) break;//转完一圈就退出}}break;}case 'N':{//南猪入侵和万箭齐发只要调用函数就行了pig[i].card[j]='X';usecard_n(i,pig[i].nxt);j=0;break;}case 'W':{pig[i].card[j]='X';usecard_w(i,pig[i].nxt);j=0;break;}case 'Z':{//装备连弩pig[i].card[j]='X';pig[i].weapon=true;use_k=true;j=0;break;}}while (pig[i].card[pig[i].cnt]=='X') pig[i].cnt--;//一个优化,清掉最后没有的牌}}}}
x#include <bits/stdc++.h>using namespace std;#define N 11#define M 2222struct player{int id;int hp;int cnt;char card[M];int pre;int nxt;int pigid;bool special;bool weapon;}pig[N];int n,m;int top;char cards[M];bool gameover;int FPcnt;void printcard(int i){bool first=true;for (int j=1;j<=pig[i].cnt;++j){if (pig[i].card[j]=='X') continue;if (!first){printf(" ");}else first=false;printf("%c",pig[i].card[j]);}printf("\n");}void getcard(int i){if (top>m) top=m;pig[i].cnt++;pig[i].card[pig[i].cnt]=cards[top];top++;}int findcard(int x,char card){for (int i=1;i<=pig[x].cnt;++i){if (pig[x].card[i]==card){pig[x].card[i]='X';return true;}}return false;}void getfriend(int x,int y){if (pig[y].pigid==0) return;if (pig[y].pigid!=3) pig[x].special=false,pig[x].pigid=1;if (pig[y].pigid==3) pig[x].special=true,pig[x].pigid=3;}void getenemy(int x,int y){if (pig[y].pigid==0) return;if (pig[y].pigid!=3) pig[x].pigid=3,pig[x].special=true;if (pig[y].pigid==3) pig[x].pigid=1,pig[x].special=false;}void dechp(int x,int i){pig[i].hp--;while (pig[i].hp<=0 && findcard(i,'P')){pig[i].hp++;}if (pig[i].hp<=0){pig[i].cnt=0;pig[i].weapon=false;if (pig[i].id==1){gameover=true;return;}else if (pig[i].id==2){if (pig[x].id==1){pig[x].cnt=0;pig[x].weapon=false;}}else if (pig[i].id==3){FPcnt--;if (FPcnt==0){gameover=true;return;}getcard(x);getcard(x);getcard(x);}pig[pig[i].pre].nxt=pig[i].nxt;pig[pig[i].nxt].pre=pig[i].pre;}}bool enemy(int x,int y){if (pig[x].id==1 && pig[y].special==true) return true;if (pig[y].pigid==0) return false;if (pig[x].id!=3 && pig[y].pigid==3) return true;if (pig[x].id==3 && pig[y].pigid!=3) return true;return false;}bool friendly(int x,int y){if (pig[y].pigid==0) return false;if (pig[x].id!=3 && pig[y].pigid!=3) return true;if (pig[x].id==3 && pig[y].pigid==3) return true;return false;}bool usecard_j(int from,int to,int last){int now=from;while (true){if ((last==0 && friendly(now,to)) || (last!=0 && enemy(now,last))){if (findcard(now,'J')){if (last==0 && friendly(now,to)) getfriend(now,to);if (last!=0 && enemy(now,last)) getenemy(now,last);if (!usecard_j(pig[now].nxt,to,now)){return true;}}}now=pig[now].nxt;if (now==from) return false;}}void usecard_k(int from,int to){getenemy(from,to);bool p=findcard(to,'D');if (p==false){dechp(from,to);}}void usecard_f(int from,int to){if (pig[from].id==1 && pig[to].id==2){dechp(from,to);return;}while (true){bool flag1=findcard(to,'K');if (!flag1){dechp(from,to);return;}bool flag2=findcard(from,'K');if (!flag2){dechp(to,from);return;}}}void usecard_n(int from,int to){while (true){if (gameover) return;if (!usecard_j(from,to,0)){bool flag=findcard(to,'K');if (!flag){if (pig[to].id==1 && pig[from].pigid==0){pig[from].special=true;}dechp(from,to);}}to=pig[to].nxt;if (to==from) return;}}void usecard_w(int from,int to){while (true){if (gameover) return;if (!usecard_j(from,to,0)){bool flag=findcard(to,'D');if (!flag){if (pig[to].id==1 && pig[from].pigid==0){pig[from].special=true;}dechp(from,to);}}to=pig[to].nxt;if (to==from) return;}}void rungame(){while (true){for (int i=1;i<=n;++i){if (gameover) return;if (pig[i].hp<=0) continue;getcard(i);getcard(i);bool use_k=true;for (int j=1;j<=pig[i].cnt;++j){if (pig[i].card[j]=='X') continue;if (gameover) return;switch (pig[i].card[j]){case 'P':{if (pig[i].hp<4){pig[i].card[j]='X';pig[i].hp++;}break;}case 'K':{if (use_k && enemy(i,pig[i].nxt)){pig[i].card[j]='X';usecard_k(i,pig[i].nxt);if (!pig[i].weapon){use_k=false;}j=0;}break;}case 'F':{if (pig[i].id==3){pig[i].card[j]='X';getenemy(i,1);if (usecard_j(i,1,0)) break;usecard_f(i,1);j=0;}else{int to=pig[i].nxt;while (true){if (enemy(i,to)){pig[i].card[j]='X';getenemy(i,to);if (usecard_j(i,to,0)) break;usecard_f(i,to);j=0;break;}to=pig[to].nxt;if (to==i) break;}}break;}case 'N':{pig[i].card[j]='X';usecard_n(i,pig[i].nxt);j=0;break;}case 'W':{pig[i].card[j]='X';usecard_w(i,pig[i].nxt);j=0;break;}case 'Z':{pig[i].card[j]='X';pig[i].weapon=true;use_k=true;j=0;break;}}while (pig[i].card[pig[i].cnt]=='X') pig[i].cnt--;}}}}int main(){scanf("%d%d",&n,&m);for (int i=1;i<N;++i){for (int j=1;j<M;++j){pig[i].card[j]='X';}pig[i].hp=4;}for (int i=1;i<=n;++i){char names[5],s[5];scanf("%s",names);for (int j=1;j<=4;++j){scanf("%s",s);pig[i].card[j]=s[0];}pig[i].cnt=4;if (names[0]=='M') pig[i].id=1,pig[i].pigid=1;else if (names[0]=='Z') pig[i].id=2;else pig[i].id=3,FPcnt++;pig[i].nxt=i+1;pig[i].pre=i-1;}pig[n].nxt=1;pig[1].pre=n;for (int i=1;i<=m;++i){char s[5];scanf("%s",s);cards[i]=s[0];}top=1;rungame();if (pig[1].hp<=0) printf("FP\n");else printf("MP\n");for (int i=1;i<=n;++i){if (pig[i].hp<=0) printf("DEAD\n");else{printcard(i);}}return 0;}