BZOJ1972: [Sdoi2010]猪国杀

题目大意:出题人给你指定了一种全新形式的自动三国杀规则,你来模拟这个过程(BZOJ题面不全,可以参考这个网站,题面很不错)


真的是一道清新可人的题呢!

//做题过程

从昨天下午4点开始写的,认认真真的写到了6点,然后去看球了...

看球的时候也写了一点点,到晚上8点一共写了6KB左右的样子

今天上午考完试之后就一直在写,大约在三点左右第一次点了编译,当时大约400行,8KB左右吧

三点半左右终于过了编,然后就是样例死循环

过了样例已经四点二十了,交了一发TLE(死循环),于是要来了数据慢慢弄

七点半AC


//做题总结

我认为这道题是一道不错的题,可以锻炼思维

这个思维不是通常的想题的思维,而是对程序整体框架的构思,我认为这个是非常重要的

写代码之前就应该大概想好框架,要不然容易出现写着写着还要推掉,还不忍心删掉的窘境

其次,这道题可以考察选手的耐心,以及...调试功底....还有....码力

这道题在2010年出到SD的省选是不是有点丧心病狂啊,根本不会有人去做好吗,(要是放到2015的AH还差不多)

做完这道题整个人都释然了

以后还会不会去碰三国杀呢?.....


//本题细节

这道题没什么题解好写....

你要记得玩家是猪!!!!!!他们会干出很多匪夷所思的事情!!

说说我出现过的所有错误吧

1.打出牌时手牌链表的头尾要注意更新

2.最开始的时候要把所有反贼的第一目标设为主公

3.反贼的决斗都会直接打向主公

4.有人死亡的时候要重新更新第一目标

5.出锦囊的人是有可能无懈掉这个锦囊的

6.出决斗的人可能死在自己回合里,这时候立即终止他的出牌阶段

7.主公杀死忠臣要扔掉诸葛连弩

8.有人在自己回合打出牌的时候,应该重置当前扫描位置(我的做法是这样)


//本题坑点

当牌堆的最后一张牌没了的时候,你需要一直摸最后一张牌

代码10K+

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 5010
using namespace std;
int bef[N],nxt[N],cnt;char kind[N];//所有玩家的手牌
char PaiDui[3010];int Top,m;//牌堆 
char MoPai()//摸走牌堆顶的牌,(如果没牌就一直抽最后一张) 
{
	if(Top!=m) Top++;
	return PaiDui[Top];
}
int ASF[11];//真实身份 1主公 2忠臣 3反贼 
int totF;//剩余反贼 
bool GameOver;//游戏是否结束 
int NowRound;//当前是谁的回合
void Sha(int,int);
void Fight(int,int);
void Nanman(int);
void Wanjian(int);
class Pig
{
	public:
	int CSF;//目前身份 0没跳 1类反 2跳忠 3跳反
	int head,last,now,TMP;//手牌链表
	int blood;//血量
	int totwx;//手中无懈可击数量
	int totp;//手中桃的数量 
	int tots;//手中闪的数量 
	int Atk;//首要攻击目标 
	int befpig,nxtpig;//存活的上一头猪和下一头猪 
	bool dead;//是否死了 
	bool Zhuge;//是否装备诸葛连弩 
	int num;//你是哪头?
	
	//调试区域开始 
	void ShouPai()
	{
		int now=head;
		cout<<blood<<' ';
		while(now)
		{
			cout<<kind[now];
			now=nxt[now];
		}
		cout<<endl;
	}
	//调试区域结束 
	
	void Bonus()
	{
		cnt++;kind[cnt]=MoPai();bef[cnt]=last;
		if(head==0) head=last=cnt;
		else nxt[last]=cnt,last=cnt;
		if(kind[cnt]=='J') totwx++;
		if(kind[cnt]=='P') totp++;
		if(kind[cnt]=='D') tots++;
		cnt++;kind[cnt]=MoPai();bef[cnt]=last;
		nxt[last]=cnt,last=cnt;
		if(kind[cnt]=='J') totwx++;
		if(kind[cnt]=='P') totp++;
		if(kind[cnt]=='D') tots++;
		cnt++;kind[cnt]=MoPai();bef[cnt]=last;
		nxt[last]=cnt,last=cnt;
		if(kind[cnt]=='J') totwx++;
		if(kind[cnt]=='P') totp++;
		if(kind[cnt]=='D') tots++;
	}
	void Punish()
	{
		head=last=now=0;
		totwx=totp=tots=0;
		Zhuge=false;
	}
	void MoPaiStage()//摸牌阶段 
	{
		cnt++;kind[cnt]=MoPai();bef[cnt]=last;
		if(head==0) head=last=cnt;
		else nxt[last]=cnt,last=cnt;
		if(kind[cnt]=='J') totwx++;
		if(kind[cnt]=='P') totp++;
		if(kind[cnt]=='D') tots++;
		cnt++;kind[cnt]=MoPai();bef[cnt]=last;
		nxt[last]=cnt,last=cnt;
		if(kind[cnt]=='J') totwx++;
		if(kind[cnt]=='P') totp++;
		if(kind[cnt]=='D') tots++;
	}
	void Use(int x)//使用一张牌(让其从链表中消失)
	{
		if(kind[x]=='J') totwx--;
		if(kind[x]=='P') totp--;
		if(kind[x]=='D') tots--;
		if(x==head&&x==last) head=0,last=0;
		else if(x==head) head=nxt[x],bef[nxt[x]]=0;
		else if(x==last) last=bef[x],nxt[bef[x]]=0;
		else bef[nxt[x]]=bef[x],nxt[bef[x]]=nxt[x];
	//	cout<<x<<' '<<head<<endl;
	}
	char Getnxt()//返回now的下一张手牌
	{
		if(!now) return 0;
		TMP=now;
		now=nxt[now];
	//	cout<<kind[tmp];
		return kind[TMP];
	}
	void Output()//输出答案 
	{
		if(dead) puts("DEAD");
		else
		{
			while(head!=0)
			{
			//	printf("%c",&kind[head]);
				cout<<kind[head];
				if(head!=last) cout<<' ';
				head=nxt[head];
			}
			puts("");
		}
	}
	int finds()//返回第一张闪的编号
	{
		now=head;
		char tmp;
		while(tmp=Getnxt())
		if(tmp=='D') return TMP;
	}
	int findp()//返回第一张桃的编号
	{
		now=head;
		char tmp;
		while(tmp=Getnxt())
		if(tmp=='P') return TMP;
	}
	int findwx()//返回第一张无懈可击的编号 
	{
		now=head;
		char tmp;
		while(tmp=Getnxt())
		if(tmp=='J') return TMP;
	}
	bool Qiusha()//尝试打出一张杀 
	{
		now=head;
		char tmp;
		while(tmp=Getnxt())
		if(tmp=='K')
		{
			Use(TMP);
			return true;
		}
		return false;
	}
	bool Qiushan()//尝试打出一张闪 
	{
		if(tots) {Use(finds());return true;}
		return false;
	}
	bool QiuTao()//尝试给出一张桃 
	{
		if(totp) {Use(findp());return true;}
		return false;
	}
	bool Qiuwx()//尝试打出一张无懈可击 
	{
		if(totwx) {Use(findwx());return true;}
		return false;
	}
	void Round()//每头猪的回合 
	{
		MoPaiStage();
		now=head;
		char tmp;
		bool usedsha=false;
	//	cout<<endl;
		while((tmp=Getnxt())&&!GameOver)
		{
	//	cout<<tmp<<' ';
			if(tmp=='D'||tmp=='J') continue;
			if(tmp=='P')
			{
				if(blood!=4) blood++,Use(TMP);
				continue;
			}
			if(tmp=='K')
			{
				if(Atk==nxtpig)
				{
					if(!usedsha||Zhuge)
					{
						Use(TMP),Sha(num,Atk);
						now=head;
						usedsha=true;
						if(GameOver) return;
					}
				}
				continue;
			}
			if(tmp=='F')
			{
				if(!Atk) continue;
				Use(TMP);
				if(ASF[num]==3) Fight(num,1);
				else Fight(num,Atk);
				now=head;
				if(GameOver||dead) return;
				continue;
			}
			if(tmp=='N')
			{
				Use(TMP);
				Nanman(num);
				now=head;
				if(GameOver) return;
				continue;
			}
			if(tmp=='W')
			{
				Use(TMP);
				Wanjian(num);
				now=head;
				if(GameOver) return;
				continue;
			}
			if(tmp=='Z')
			{
				Use(TMP);
				Zhuge=true;
				now=head;
				continue;
			}
		}
	}
}pig[11];
void Recal(int x)
{
	int y=pig[x].nxtpig;
	if(ASF[x]==1)
	{
		while(y!=x)
		{
			if(pig[y].CSF==1||pig[y].CSF==3)
			{
				pig[x].Atk=y;
				return;
			}
			y=pig[y].nxtpig;
		}
		pig[x].Atk=0;
	}
	else if(ASF[x]==2)
	{
		while(y!=x)
		{
			if(pig[y].CSF==3)
			{
				pig[x].Atk=y;
				return;
			}
			y=pig[y].nxtpig;
		}
		pig[x].Atk=0;
	}
	else
	{
		while(y!=x)
		{
			if(pig[y].CSF==2||ASF[y]==1)
			{
				pig[x].Atk=y;
				return;
			}
			y=pig[y].nxtpig;
		}
		pig[x].Atk=0;
	}
}
void Allrecal()
{
	int x=pig[1].nxtpig;
	Recal(1);
	while(x!=1)
	{
		Recal(x);
		x=pig[x].nxtpig;
	}
}
void Kill(int x,int y)
{
	pig[y].dead=true;
	if(ASF[y]==1) {GameOver=true;return;}
	if(ASF[y]==3)
	{
		totF--;
		if(totF==0) {GameOver=true;return;}
		pig[x].Bonus();
	}
	if(ASF[y]==2&&ASF[x]==1)
	pig[x].Punish();
	int BEF=pig[y].befpig,NXT=pig[y].nxtpig;
	pig[BEF].nxtpig=NXT;
	pig[NXT].befpig=BEF;
	Allrecal();
}
void Hurt(int x,int y)
{
	pig[y].blood--;
	if(pig[y].blood==0)
	{
		if(pig[y].QiuTao()) pig[y].blood++;
		else Kill(x,y);
	}
}
void Sha(int x,int y)//杀事件 
{
	if(ASF[x]!=1&&pig[x].CSF<2)
	{
		if(ASF[y]==3) pig[x].CSF=2;
		else pig[x].CSF=3;
		Allrecal();
	}
	if(pig[y].Qiushan()) return;
	Hurt(x,y);
}
bool startwxcycle(int st,bool YisFan)
{
	bool ST=YisFan;
	int lastdachu=st,x=st;
	if(YisFan==(ASF[x]==3))
	{
		if(pig[x].Qiuwx())
		{
			lastdachu=x;
			YisFan^=1;
			if(pig[x].CSF<=2)
			{
				pig[x].CSF=3-YisFan;
				Allrecal();
			}
		}
	}
	x=pig[x].nxtpig;
	while(x!=lastdachu)
	{
		if(YisFan==(ASF[x]==3))
		{
			if(pig[x].Qiuwx())
			{
				lastdachu=x;
				YisFan^=1;
				if(pig[x].CSF<=2)
				{
					pig[x].CSF=3-YisFan;
					Allrecal();
				}
			}
		}
		x=pig[x].nxtpig;
	}
	return (ST!=YisFan);
}
void Fight(int x,int y)//决斗事件
{
	if(ASF[x]!=1&&pig[x].CSF<2)
	{
		if(ASF[y]==3) pig[x].CSF=2;
		else pig[x].CSF=3;
		Allrecal();
	}
	if(ASF[y]==1||pig[y].CSF>=2)
	{
		if(ASF[y]==1||pig[y].CSF==2)
		{
			if(startwxcycle(x,0))
			return;
		}
		else
		{
			if(startwxcycle(x,1))
			return;
		}
	}
	if(ASF[x]==1&&ASF[y]==2)
	Hurt(x,y);
	else
	{
		while(1)
		{
			if(!pig[y].Qiusha()) {Hurt(x,y);return;}
			if(!pig[x].Qiusha()) {Hurt(y,x);return;}
		}
	}
}
void Nanman(int x)//南蛮事件
{
	int y=pig[x].nxtpig;
	while(y!=x)
	{
		if(ASF[y]==1||pig[y].CSF>=2)
		{
			if(ASF[y]==1||pig[y].CSF==2)
			{
				if(startwxcycle(x,0))
				{
					y=pig[y].nxtpig;
					continue;
				}
			}
			else
			{
				if(startwxcycle(x,1))
				{
					y=pig[y].nxtpig;
					continue;
				}
			}
		}
		if(!pig[y].Qiusha())
		{
			Hurt(x,y);
			if(GameOver) return;
			if(y==1&&pig[x].CSF==0)
			{
				pig[x].CSF=1;
				Allrecal();
			}
		}
		y=pig[y].nxtpig;
	}
}
void Wanjian(int x)//万箭事件
{
	int y=pig[x].nxtpig;
	while(y!=x)
	{
		if(ASF[y]==1||pig[y].CSF>=2)
		{
			if(ASF[y]==1||pig[y].CSF==2)
			{
				if(startwxcycle(x,0))
				{
					y=pig[y].nxtpig;
					continue;
				}
			}
			else
			{
				if(startwxcycle(x,1))
				{
					y=pig[y].nxtpig;
					continue;
				}
			}
		}
		if(!pig[y].Qiushan())
		{
			Hurt(x,y);
			if(GameOver) return;
			if(y==1&&pig[x].CSF==0)
			{
				pig[x].CSF=1;
				Allrecal();
			}
		}
		y=pig[y].nxtpig;
	}
}

int main()
{
//	freopen("kopk6.in","r",stdin);
	int n;
	scanf("%d%d",&n,&m);
	int i,j,x=0,y;
	char o[10];
	for(i=1;i<n;i++) pig[i].nxtpig=i+1;pig[n].nxtpig=1;
	for(i=2;i<=n;i++) pig[i].befpig=i-1;pig[1].befpig=n;
	for(i=1;i<=n;i++)
	{
		scanf("%s",o);
		if(o[0]=='M') ASF[i]=1;
		else if(o[0]=='Z') ASF[i]=2;
		else if(o[0]=='F') ASF[i]=3,totF++;
		scanf("%s",o);x++;PaiDui[x]=o[0];
		scanf("%s",o);x++;PaiDui[x]=o[0];
		scanf("%s",o);x++;PaiDui[x]=o[0];
		scanf("%s",o);x++;PaiDui[x]=o[0];//先把牌都插到牌堆里 
	}
	for(i=1;i<=m;i++)
	scanf("%s",o),x++,PaiDui[x]=o[0];
	m+=4*n;
	for(i=1;i<=n;i++)
	{
		pig[i].MoPaiStage();pig[i].MoPaiStage();
		pig[i].num=i;
		pig[i].blood=4;//初始化每头猪 
	}
	i=1;
	Allrecal();
	while(!GameOver)
	{
		NowRound=i;
	/*	for(j=1;j<=n;j++)
		pig[j].ShouPai();
		cout<<endl;*/
		pig[i].Round();
	/*	for(j=1;j<=n;j++)
		pig[j].ShouPai();
		cout<<endl;*/
		i=pig[i].nxtpig;
	}
	if(pig[1].dead) puts("FP");
	else puts("MP");
	for(i=1;i<=n;i++)
	pig[i].Output();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值