连写带调歪歪了一天半。。。。。。
注意理解题意上的坑点:
1、类反猪在未亮明身份时,只有主猪会对其表敌意,其他反猪均将其看作未亮明身份的猪,不会对其表敌意or献殷勤。
2、献殷勤or表敌意的对象只会是已亮明身份的猪(顺便注意:第一次献殷勤or表敌意的玩家身份就亮明了)。
3、关于无懈的结算和使用顺序:
(题目原话)每次有一张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会;
举个栗子:
某玩家A出了张万箭,玩家B询问是否有人愿意替他出无懈挡,这个询问先从A开始。如果这时A出了无懈,关于A的无懈的询问(即是否有玩家出无懈抵消A的无懈)应从A逆时针往下第一位询问。
4、玩家x->y的距离并不一定等于玩家y->x的距离(原题题干:距离:两只猪的距离定义为沿着逆时针方向间隔的猪数+1)。
理解好题意后,我们想一想怎么写。
1、维护玩家之间的敌对关系:
我是用一个数组记录每一个人的真实身份(主:1 忠:2 反:3),又用一个数组
记录当前玩家的真实身份。未表明身份
值=0,否则=该玩家的
值。对于主公认定的未表明身份的“类反猪”,单独开一个
数组来记。
且
的玩家即为“类反猪”。
两个玩家之间的关系判定利用以上三个数组数组暴力判即可。
2、对于锦囊牌:
void 函数名(使用锦囊玩家编号x)
{
for (i:除x之外的所有玩家)
if 玩家i符合使用条件
对玩家i询问无懈
无懈成功:(决斗)return
(南猪or万箭)continue;
无懈失败:
出杀or闪环节
判定减血
}
3、杀的出法和上面差不多。具体细节见代码。
4、无懈的判定:我是用两个函数维护的。
int wuxie(int x)
//询问x的无懈可击是否成功(注意:从使用无懈的人的逆时针方向下一位开始) 无懈成功返回1,失败返回0
{
int now=x,flag=0;
for(ri i=1;i<=n-1;i++)
{
now++;
if(now>n) now=1;
if(dead[now]) continue;
int pla=hadwuxie(now);
if(!pla) continue;
if(ming[x]==0&&who[now]==1&&killz[now]==1)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;//无懈成功or失败利用异或维护
}
if(ming[x]==1&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
if(ming[x]==2&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
if(ming[x]==3)
{
if(who[now]==2||who[now]==1)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
}
}
return 1;
}
int attack(int x,int from)//询问被锦囊攻击的一方是否有无懈替其抵挡。抵挡成功返回1,失败返回0
//注意:对于锦囊的被攻击方,询问无懈从使用南猪or决斗or万箭的一方开始
{
int now=from-1,flag=0;
for(ri i=1;i<=n;i++)
{
now++;
if(now>n) now=1;
if(dead[now]) continue;
int pla=hadwuxie(now);
if(!pla) continue;
if(ming[x]==1&&who[now]<=2)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
if(ming[x]==2&&who[now]<=2)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
if(ming[x]==3&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
}
return 0;
}
剩下的就全是细节了(我的细节上的锅有点多了emmm)
Code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#define ri register int
using namespace std;
const int NMAXN=15,MMAXN=2020;
int n,m,mtot,who[NMAXN],cardtot[NMAXN],cardhad[NMAXN],blood[NMAXN],akhad[NMAXN],tmptot;
int shanow[NMAXN],ming[NMAXN],killz[NMAXN],dead[NMAXN],result;
char ss[MMAXN],card[NMAXN][MMAXN],tmp[MMAXN];
string whonow;
int pd()//判断某局面是否有一方满足胜利条件 ok
{
if(dead[1]==1) return 2;//主死反胜result=2
int totz=0,totf=0;
for(ri i=1;i<=n;i++)
if(!dead[i])
{
if(who[i]<=2) totz++;
if(who[i]==3) totf++;
}
if(totz==0) return 2;//反胜result=2
if(totf==0) return 1;//主胜result=1
return 0;
}
void jiesuan()//游戏结束时的结算 ok
{
if(result==1) cout<<"MP"<<'\n';
if(result==2) cout<<"FP"<<'\n';
for(ri i=1;i<=n;i++)
{
if(dead[i]) { cout<<"DEAD"<<'\n'; continue; }
for(int j=1;j<=cardtot[i];j++)
if('A'<=card[i][j]&&card[i][j]<='Z') cout<<card[i][j]<<" ";
cout<<'\n';
}
}
int dis(int x,int y)//计算两人的距离 (注意x->y和y->x的距离是不一个意义的)
{
int tot=0,now=x;
if(x<y)
{
for(ri i=x+1;i<=y-1;i++)
if(!dead[i]) tot++;
return tot+1;
}
for(ri i=1;i<=n-(x-y+1);i++)
{
now++;
if(now>n) now=1;
if(!dead[now]) tot++;
}
return tot+1;
}
int hadsha(int x)//玩家是否有杀 有返回1,无返回0
{
for(ri k=1;k<=cardtot[x];k++)
if(card[x][k]=='K') { card[x][k]='0'; return 1; }
return 0;
}
int hadshan(int x)//玩家是否有闪 有返回1,无返回0
{
for(ri k=1;k<=cardtot[x];k++)
if(card[x][k]=='D') { card[x][k]='0'; return 1; }
return 0;
}
int hadwuxie(int x)//玩家是否有无懈可击 有返回1,无返回0
{
for(ri k=1;k<=cardtot[x];k++)
if(card[x][k]=='J') return k;
return 0;
}
int tao(int x)//濒死状态下吃桃 成功:0 失败:1
{
for(ri i=1;i<=cardtot[x];i++)
{
if(card[x][i]=='P')
{
card[x][i]='0',blood[x]++;
if(blood[x]>0) break;
}
}
if(!blood[x]) return 1;
return 0;
}
void mopai(int x,int tot)//玩家摸牌 ok
{
for(ri i=1;i<=tot;i++)
{
if(mtot<m) mtot++;
card[x][++cardtot[x]]=ss[mtot];
}
}
void jianxie(int x,int from)//某玩家被减了一血,结算 x:减血者 from:伤害来源 ok
{
blood[x]-=1;
if(blood[x]==0)
{
int flag=tao(x);
if(flag)
{
dead[x]=1;
result=pd();
if(result) { jiesuan(); exit(0); }
if(who[x]==2&&who[from]==1) { cardtot[from]=0; akhad[from]=0; return; }
//调了半个小时的Bug;主杀忠后装备牌也应弃置(akhad[from]=0;)
if(who[x]==3) mopai(from,3);
}
}
}
int checkene(int x,int y)//检查x是否会判定y为敌人(是1否0) ok
{
if(ming[y]==0&&killz[y]==0) return 0;
if(who[x]==1)
{
if(ming[y]==2) return 0;
if(ming[y]==0&&killz[y]==1) return 1;
}
if(who[x]==2&&ming[y]==1) return 0;
if(who[x]==2&&ming[y]==2) return 0;
if(who[x]==3&&ming[y]==3) return 0;
return 1;
}
void sha(int x,int pla)//杀
{
int now=x,flag=0;
if((!akhad[x])&&shanow[x]==1) return;
if(who[x]==3&&dis(x,1)==1)
{
card[x][pla]='0',shanow[x]+=1,cardhad[x]++; //yes:标记该张杀有没有出
//注意:杀在出出去后才标记该人使用杀的次数+1(shanow[x]+=1)
if(!ming[x]||ming[x]!=who[x]) ming[x]=who[x];
flag=hadshan(1);//flag:标记该张杀有没有杀到人
if(!flag) jianxie(1,x);
return;
}
for(ri i=1;i<=n-1;i++)
{
now++;
if(dead[now]) continue;
if(now>n) now=1;
if(!checkene(x,now)||dis(x,now)!=1) continue;
card[x][pla]='0',shanow[x]+=1,cardhad[x]++;
if(!ming[x]||who[x]!=ming[x]) ming[x]=who[x];
flag=hadshan(now);//flag:标记该张杀有没有杀到人
if(!flag) jianxie(now,x);
if(card[x][pla]=='0') break;
}
return;
}
int wuxie(int x)
//询问x的无懈可击是否成功(注意:从使用无懈的人的逆时针方向下一位开始) 无懈成功返回1,失败返回0
{
int now=x,flag=0;
for(ri i=1;i<=n-1;i++)
{
now++;
if(now>n) now=1;
if(dead[now]) continue;
int pla=hadwuxie(now);
if(!pla) continue;
if(ming[x]==0&&who[now]==1&&killz[now]==1)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;//无懈成功or失败利用异或维护
}
if(ming[x]==1&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
if(ming[x]==2&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
if(ming[x]==3)
{
if(who[now]==2||who[now]==1)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag^1;
}
}
}
return 1;
}
int attack(int x,int from)//询问被锦囊攻击的一方是否有无懈替其抵挡。抵挡成功返回1,失败返回0
//注意:对于锦囊的被攻击方,询问无懈从使用南猪or决斗or万箭的一方开始
{
int now=from-1,flag=0;
for(ri i=1;i<=n;i++)
{
now++;
if(now>n) now=1;
if(dead[now]) continue;
int pla=hadwuxie(now);
if(!pla) continue;
if(ming[x]==1&&who[now]<=2)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
if(ming[x]==2&&who[now]<=2)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
if(ming[x]==3&&who[now]==3)
{
if(!ming[now]) ming[now]=who[now];
card[now][pla]='0';
flag=wuxie(now);
return flag;
}
}
return 0;
}
void juedou(int x,int pla)//决斗
{
int flag=0,now=x;
for(ri i=1;i<=n-1;i++)
{
now++;
if(now>n) now=1;
if(checkene(x,now)&&(!dead[now])) { flag=1; break; }
}
if(who[x]==3) flag=1,now=1;
if(!flag) return;
card[x][pla]='0',cardhad[x]++;
if(!ming[x]||who[x]!=ming[x]) ming[x]=who[x];//亮明身份
flag=attack(now,x);
if(flag) return;
if(who[now]==2&&who[x]==1) { jianxie(now,x); return; }
int had1=hadsha(now),had2;//被杀对象will先出杀
if(!had1) { jianxie(now,x); return; }
while(1)//交替减血
{
had1=hadsha(x);
if(!had1) { jianxie(x,now); return; }
had2=hadsha(now);
if(!had2) { jianxie(now,x); return; }
}
return;
}
void nanzhu(int x)//南猪入侵
{
int now=x,flag;
for(ri i=1;i<=n-1;i++)//i:被南猪入侵的玩家
{
now++;
if(now>n) now=1;
if(dead[now]) continue;
flag=attack(now,x);
if(flag) continue;
flag=hadsha(now);
if(!flag)
{
jianxie(now,x);
if(!ming[x]&&now==1) killz[x]=1;
}
}
}
void wanjian(int x)//万箭齐发
{
int now=x,flag;
for(ri i=1;i<=n-1;i++)//i:i:被万箭袭击的玩家
{
now++;
if(now>n) now=1;
if(dead[now]) continue;//时刻注意不结算已经gg的玩家
flag=attack(now,x);
if(flag) continue;
flag=hadshan(now);
if(!flag)
{
jianxie(now,x);
if(!ming[x]&&now==1) killz[x]=1;
}
}
}
void work()//模拟回合进行函数
{
while(1)
{
for(ri k=1;k<=n;k++)//k:当前出牌的人的编号
{
if(dead[k]) continue;//gg的玩家不出牌
mopai(k,2);//摸牌
shanow[k]=0,cardhad[k]=1;//清空当前玩家出杀的次数
while(cardhad[k]>0)
{
if(dead[k]) break;//玩家有可能在使用牌的过程中挂掉(比如一血用决斗结果被干)
cardhad[k]=0;
for(ri i=1;i<=cardtot[k];i++)//牌的编号
{
if(dead[k]) break;//玩家有可能在使用牌的过程中挂掉(比如一血用决斗结果被干)
if(card[k][i]=='P'&&blood[k]<4) { blood[k]++; card[k][i]='0'; cardhad[k]++; }//桃
if(card[k][i]=='K') sha(k,i);//杀
if(card[k][i]=='F') juedou(k,i);//决斗
if(card[k][i]=='N') { card[k][i]='0'; nanzhu(k); cardhad[k]++; }//南猪入侵
if(card[k][i]=='W') { card[k][i]='0'; wanjian(k); cardhad[k]++; }//万箭齐发
if(card[k][i]=='Z') { card[k][i]='0'; akhad[k]=1; cardhad[k]++; }//装AK
}
}
tmptot=0;
for(ri i=1;i<=cardtot[k];i++)
if('A'<=card[k][i]&&card[k][i]<='Z') tmp[++tmptot]=card[k][i];
for(ri i=tmptot+1;i<=cardtot[k];i++) card[k][i]='0';
for(ri i=1;i<=tmptot;i++) card[k][i]=tmp[i];
cardtot[k]=tmptot;
}
}
}
void shuru()//初始化信息函数
{
scanf("%d%d",&n,&m);
for(ri i=1;i<=n;i++)
{
cin>>whonow;
if(whonow=="MP") who[i]=1;
if(whonow=="ZP") who[i]=2;
if(whonow=="FP") who[i]=3;
for(ri j=1;j<=4;j++) cin>>card[i][j];//初始化卡牌
cardtot[i]=4,blood[i]=4;//初始化血量,卡牌数
}
for(ri i=1;i<=m;i++) cin>>ss[i];//初始化牌堆
ming[1]=1;//表示某人是否亮明身份
}
int main()//主函数
{
shuru();
work();
return 0;
}