题解 P2482 【[SDOI2010]猪国杀】
之前这个代码有些注释有bug,现已修复重新提交【给我过吧
首先我的这段代码参考过了hzwerdalao的做法但是大概架构是我打的只是有些小bug和他的代码对拍而已QAQ
四位dalao都把一些注意事项和小坑都给列出来了,我就贴个有注释的代码吧……【打了我四个中午还鸽了一会QAQ】
/*
牌库为空之后再抽牌,会重复抽最后一张被抽走牌
主公死或反贼全死都中断游戏,直接进入输出阶段
所有人一开始都知道主公的身份
每个人都会无条件帮队友无懈掉决斗【万箭】【南蛮】
每个人都会无条件【无懈】掉对手的【无懈】
每个人都不会【无懈】掉队友的【无懈】
反贼只会【决斗】主公
忠臣被主公【决斗】并不能算跳忠
主公杀了忠臣要清空所有牌以及【诸葛连弩】
杀死反贼摸三张牌
*/
/*
桃 P
杀 K
闪 D
决斗 F
南蛮入侵 N
万箭齐发 W
无懈可击 J
诸葛连弩 Z
*/
#include<bits/stdc++.h>
using namespace std;
struct node{
int cs,hp,next,last;
//cs=cardsize=手牌数
//hp 生命值
char id,card[2010];
//id=identity=身份
bool zgln;
//是否装备了【诸葛连弩】
}a[20];
char kn[11],kpd[2010],sss[10];
//kn表示在主公眼里这只猪的身份
//kpd 卡牌堆
int n,m,fz;
//fz 反贼数量
bool ed;
void mp(int x)
//【摸牌】
{
if(!m) m++;
a[x].card[++a[x].cs]=kpd[m];
m--;
}
void js(int x1,int x2)
//【击杀】
{
for(int i=1;i<=a[x2].cs;i++)
if(a[x2].card[i]=='P')
//判断是否有【桃】
{
a[x2].card[i]='U';
a[x2].hp++;
return ;
}
a[a[x2].next].last=a[x2].last;
a[a[x2].last].next=a[x2].next;
//死亡后改变攻击距离
if(x2==1){ed=true;return ;}
if(a[x2].id=='F') fz--;
if(!fz){ed=true;return ;}
//没有反贼游戏结束
if(a[x2].id=='F') mp(x1),mp(x1),mp(x1);
//击杀反贼摸三张牌
if(a[x2].id=='Z' && a[x1].id=='M') a[x1].cs=0,a[x1].zgln=false;
//如果主公把忠臣杀了那就要弃牌
}
void Kil(int x1,int x2)
//【杀】
{
for(int i=1;i<=a[x2].cs;i++)
if(a[x2].card[i]=='D')
{
a[x2].card[i]='U';
return ;
}
a[x2].hp--;
if(!a[x2].hp) js(x1,x2);
//每次造成伤害都要判断被攻击者是否空血
//然后进入【击杀】环节
}
bool wxkj(int x1,int x2,int x3)
//【无懈可击】
{
int i=x1,pd=x3?x2:x1;
while(1)
{
if(x3==1)
{
if(kn[x2]==a[i].id || (kn[x2]=='M' && a[i].id=='Z') || (kn[x2]=='Z' && a[i].id=='M'))
//假如是敌对的那就【无懈可击】掉
for(int j=1;j<=a[i].cs;j++)
if(a[i].card[j]=='J')
{
a[i].card[j]='U';
kn[i]=a[i].id;
return !wxkj(i,x1,0);
}
}
else
{
if(((a[i].id=='M' || a[i].id=='Z') && kn[x1]=='F') || (a[i].id=='F' && (kn[x1]=='M' || kn[x1]=='Z')))
for(int j=1;j<=a[i].cs;j++)
if(a[i].card[j]=='J')
{
a[i].card[j]='U';
kn[i]=a[i].id;
return !wxkj(i,x1,0);
}
}
i=a[i].next;
if(i==x1) break;
//没有人用【无懈可击】抵挡此【无懈可击】那么这张牌就生效
}
return false;
}
void nmrq(int x1)
//【南蛮入侵】
{
for(int x2=a[x1].next;x2!=x1;x2=a[x2].next)
//进行一个循环来出牌
if(!wxkj(x1,x2,1))
//判断是否被【无懈可击】掉
{
int i;
for(i=1;i<=a[x2].cs;i++)
if(a[x2].card[i]=='K')
{
a[x2].card[i]='U';
break;
}
if(i>a[x2].cs)
{
a[x2].hp--;
if(x2==1 && kn[x1]=='U') kn[x1]='L';
if(!a[x2].hp) js(x1,x2);
if(ed) return ;
}
}
}
void wjqf(int x1)
//【万箭齐发】
{
for(int x2=a[x1].next;x2!=x1;x2=a[x2].next)
if(!wxkj(x1,x2,1))
//判断是否被【无懈可击】掉
{
int i;
for(i=1;i<=a[x2].cs;i++)
if(a[x2].card[i]=='D')
{
a[x2].card[i]='U';
break;
}
if(i>a[x2].cs)
{
a[x2].hp--;
if(x2==1 && kn[x1]=='U') kn[x1]='L';
if(!a[x2].hp) js(x1,x2);
if(ed) return ;
}
}
}
void jd(int x1,int x2)
//【决斗】
{
int i,j,k;
if(wxkj(x1,x2,1)) return ;
//判断是否被【无懈可击】掉
if(x1==1 && a[x2].id=='Z')
{
a[x2].hp--;
if(!a[x2].hp) js(x1,x2);
return ;
}
j=k=1;
while(1)
{
while(a[x2].card[j]!='K' && j<=a[x2].cs) j++;
if(j>a[x2].cs)
{
a[x2].hp--;
if(!a[x2].hp) js(x1,x2);
return ;
}
else a[x2].card[j]='U';
while(a[x1].card[k]!='K' && k<=a[x1].cs) k++;
if(k>a[x1].cs)
{
a[x1].hp--;
if(!a[x1].hp) js(x2,x1);
return ;
}
else a[x1].card[k]='U';
}
}
void hh()
//进入回合
{
char nc;
ed=true;
if(fz) ed=false;
if(ed) return ;
for(int i=1;i;i=a[i].next)
{
mp(i),mp(i);
bool kill=true;
for(int j=1;j<=a[i].cs;j++)
if(a[i].card[j]!='U')
//=='U'就是被使用过,弃置了
{
if(!a[i].hp) break;
nc=a[i].card[j];
//nc=now-card=现在的手牌
if(nc=='P')
//使用【桃】
{
if(a[i].hp!=4) a[i].hp++,a[i].card[j]='U';
continue;
}
if(nc=='K')
//使用【杀】
{
if(!kill && !a[i].zgln) continue;
if(a[i].id=='M' && kn[a[i].next]!='L' && kn[a[i].next]!='F') continue;
if(a[i].id=='Z' && kn[a[i].next]!='F') continue;
if(a[i].id=='F' && kn[a[i].next]!='Z' && kn[a[i].next]!='M') continue;
a[i].card[j]='U';
Kil(i,a[i].next);
kn[i]=a[i].id,kill=false;
if(ed) return ;
continue;
}
if(nc=='F')
//使用【决斗】
{
if(a[i].id=='F')
{
a[i].card[j]='U',jd(i,1);
kn[i]=a[i].id;
if(ed) return ;
j=0;
continue;
}
for(int k=a[i].next;k!=i;k=a[k].next)
if((a[i].id=='M' && (kn[k]=='L' || kn[k]=='F')) || (a[i].id=='Z' && kn[k]=='F'))
{
a[i].card[j]='U',jd(i,k);
kn[i]=a[i].id;
if(ed) return ;
j=0;
break;
}
continue;
}
if(nc=='N')
//使用【南蛮入侵】
{
a[i].card[j]='U';
nmrq(i);
if(ed) return ;
j=0;
continue;
}
if(nc=='W')
//使用【万箭齐发】
{
a[i].card[j]='U';
wjqf(i);
if(ed) return ;
j=0;
continue;
}
if(nc=='Z')
//装备【诸葛连弩】
{
a[i].zgln=true;
a[i].card[j]='U';
j=0;
continue;
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) a[i].next=i+1,a[i].last=i-1;
//攻击距离
a[n].next=1,a[1].last=n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<2010;j++) a[i].card[j]='U';
scanf("%s",sss);a[i].id=sss[0];
for(int j=1;j<=4;j++) scanf("%s",sss),a[i].card[j]=sss[0];
a[i].cs=a[i].hp=4;
//手牌上限和血量上限都是4
if(a[i].id=='F') fz++;
//统计反贼的数量
a[i].zgln=false;
}
for(int i=2;i<=n;i++) kn[i]='U';
kn[1]='M';
for(int i=1;i<=m;i++) scanf("%s",sss),kpd[m-i+1]=sss[0];
hh();
//进入回合
if(a[1].hp<=0) printf("FP\n");
else printf("MP\n");
//看看主公有没有挂
for(int i=1;i<=n;i++)
{
if(a[i].hp<=0) printf("DEAD\n");
//空血凉凉
else
//亮牌
{
for(int j=1;j<=a[i].cs;j++)
if(a[i].card[j]!='U') printf("%c ",a[i].card[j]);
//若该手牌没有被弃置则输出
printf("\n");
}
}
return 0;
}