P2482 [SDOI2010] 猪国杀 解题报告

P2482 [SDOI2010] 猪国杀

打了三天过了

爽!!!!!

回合架构

循环+死亡判断+结束判断

摸牌

K F N W Z

无懈可击

无懈可击分为两类:无懈可击其他锦囊牌、无懈可击无懈可击。判断的差别在于前者可以同阵营造成伤害,后者只能不同阵营互掐

易错点

1.无懈可击应从出牌人本身开始询问。例如1号位放万箭,无懈从1号开始询问。但若3号位出无懈,想无懈此无懈应从3号位开始询问。

2.注意猪哥连弩不能到手就用(75pts)

3.有些细节的地方不要手滑

4.决斗忠猪不反抗主猪不算献殷勤

code

/*基本牌:桃 P 杀 K 闪 D
锦囊牌:决斗 F  南猪入侵 N 万箭齐发 W 无懈可击 J
装备牌:猪哥连弩 Z 
自己造的:E empty 表示空牌 

hostility 表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤;
complaisance 献殷勤:使用无懈可击挡下南猪入侵、万箭齐发、决斗;使用无懈可击抵消表敌意;
跳忠:通过行动表示自己是忠猪。对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意;
跳反:通过行动表示自己是反猪。对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤。
忠猪不会跳反,反猪也不会跳忠;不管是忠猪还是反猪,能够跳必然跳。
*/
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define pii pair<int,int>
const int maxn=12,maxm=1e5+10; 
int n,m;
int fz_tot;//反猪数量 
int ed=0;//2反贼赢 1忠猪赢 
double t;
struct IDcard{
	int id;//编号顺序 
	int nxt,pre;//前后  双向链表维护 
	string cst;//身份成分constituent
	char card[maxm];//牌堆 
	int card_tot;//牌数 
	bool zgln;//是否配备猪哥连弩
	int hp;//血量
	bool die;//是否死掉
	bool jump;//是否跳(反/忠) 
	bool sim;//是否是类反猪
}pig[maxn];
queue<char>card_heap;
void init(){
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		cin>>pig[i].cst;
		if(pig[i].cst=="FP")fz_tot++;
		pig[i].card_tot=0;
		pig[i].id=i;
		pig[i].hp=4;
		pig[i].zgln=0;
		pig[i].nxt=i+1;
		pig[i].pre=i-1;
		pig[i].sim=0;
		pig[i].jump=0;
		pig[i].die=0;
		for(int j=1;j<=4;++j)
			cin>>pig[i].card[++pig[i].card_tot];
	}
	pig[1].pre=n;
	pig[n].nxt=1;
	for(int i=1;i<=m;++i){
		char pai;
		cin>>pai;
		card_heap.push(pai);
	}
	pig[1].jump=1;
}
void get_card(int x){
	if(card_heap.size()==1)card_heap.push(card_heap.front());
	pig[x].card[++pig[x].card_tot]=card_heap.front();
	card_heap.pop();
}
void js(int x,int s){//x hp<=0时,s伤害来源  
	for(int i=1;i<=pig[x].card_tot;++i){
		if(pig[x].card[i]=='P'){
			pig[x].hp++;
			pig[x].card[i]='E';
		}
		if(pig[x].hp>=1)return ;
	}
	pig[x].die=1;
	int nxt=pig[x].nxt;
	int pre=pig[x].pre;
	pig[pre].nxt=nxt;
	pig[nxt].pre=pre;
	if(pig[x].cst=="FP")fz_tot--;
	if(pig[x].cst=="MP"){ed=2;return ;}
	if(!fz_tot){ed=1;return ;}
	if(pig[x].cst=="FP")get_card(s),get_card(s),get_card(s);
	if(pig[x].cst=="ZP"&&pig[s].cst=="MP"){
		pig[s].zgln=0;
		pig[s].card_tot=0;
	}
}
void use_K(int u,int v){//u 对 v 使用 K
	//表敌意 
	if(pig[v].cst=="MP")pig[u].jump=1,pig[u].sim=0;
	if(pig[v].jump)pig[u].jump=1,pig[u].sim=0;
	for(int i=1;i<=pig[v].card_tot;++i){
		if(pig[v].card[i]=='D'){
			pig[v].card[i]='E';
			return ;
		}
	}
	pig[v].hp--;
	if(pig[v].hp<=0)js(v,u);
}
bool wxkj(int x1,int x2,int op){//x1对x2出牌 x2寻求同伴(自己)无懈 有/无 1/0 
	int i=x1;
	while(1){
		if(op==1){//帮x2出无懈可击 上一张是其他锦囊牌(可能对队友造成伤害)//没有亮明 队友(自己)不无懈 
			if(pig[x2].jump||x2==1)if((pig[i].cst=="FP"&&pig[x2].cst=="FP")||((pig[i].cst=="MP"||pig[i].cst=="ZP")&&(pig[x2].cst=="ZP"||x2==1))){
				for(int j=1;j<=pig[i].card_tot;++j){
					if(pig[i].card[j]=='J'){
						pig[i].card[j]='E';
						if(pig[x2].jump||x2==1)pig[i].jump=1,pig[i].sim=0;
						return !wxkj(i,x1,0);
					}
				}
			}
		}else {//上一轮除了无懈可击 不让上一轮i,这一轮X1得逞  算是献殷勤,一定可以发牌 x1已暴露身份 
			if((pig[i].cst=="MP"||pig[i].cst=="ZP")&&pig[x1].cst=="FP"||(pig[x1].cst=="MP"||pig[x1].cst=="ZP")&&pig[i].cst=="FP"){
				for(int j=1;j<=pig[i].card_tot;++j){
					if(pig[i].card[j]=='J'){
						pig[i].card[j]='E';
						if(pig[x1].jump||x1==1)pig[i].jump=1,pig[i].sim=0;
						return !wxkj(i,x1,0);
					}
				}
			}
		}
		i=pig[i].nxt;
		if(i==x1)break;
	}
	return 0;
}
void jd(int x1,int x2){//x1对x2决斗
	if(wxkj(x1,x2,1))return ;//被无懈了
	if(pig[x2].cst=="ZP"&&x1==1){
		pig[x2].hp--;
		if(!pig[x2].hp)js(x2,1);
		return ;
	}
	int i=1,j=1;
	pig[x2].card[pig[x2].card_tot+1]='E';//防止脏数据 
	pig[x1].card[pig[x1].card_tot+1]='E';
	while(1){
		while(pig[x2].card[j]!='K'&&j<=pig[x2].card_tot)j++;
		if(j>pig[x2].card_tot){
			pig[x2].hp--;
			if(pig[x2].hp<=0)js(x2,x1);
			return ;
		}else {
			pig[x2].card[j]='E';
		}
		while(pig[x1].card[i]!='K'&&i<=pig[x1].card_tot)i++;
		if(i>pig[x1].card_tot){
			pig[x1].hp--;
			if(pig[x1].hp<=0)js(x1,x2);
			return ;
		}else {
			pig[x1].card[i]='E';
		}
	}
}
void nzrq(int x1){//此处无懈可击仅对 1 个角色产生效果
	for(int x2=pig[x1].nxt;x2!=x1;x2=pig[x2].nxt){
		bool flg=0;
		if(wxkj(x1,x2,1))continue;
		for(int i=1;i<=pig[x2].card_tot;++i){
			if(pig[x2].card[i]=='K'){
				pig[x2].card[i]='E';
				flg=1;
				break ;
			}
		}
		if(flg)continue;
		pig[x2].hp--;
		if(x2==1&&pig[x1].jump==0)pig[x1].sim=1;//造成伤害,类反 
		if(pig[x2].hp<=0)js(x2,x1);
		if(ed)return ;
	}
}
void wjqf(int x1){//此处无懈可击仅对 1 个角色产生效果 
	for(int x2=pig[x1].nxt;x2!=x1;x2=pig[x2].nxt){
		bool flg=0;
		if(wxkj(x1,x2,1))continue;
		for(int i=1;i<=pig[x2].card_tot;++i){
			if(pig[x2].card[i]=='D'){
				pig[x2].card[i]='E';
				flg=1;
				break;
			}
		}
		if(flg)continue;
		pig[x2].hp--;
		if(x2==1&&pig[x1].jump==0)pig[x1].sim=1;
		if(pig[x2].hp<=0)js(x2,x1);
		if(ed)return ;
	}
}
void debug(){
	for(int i=1;i<=n;++i)
		for(int j=1;j<=pig[i].card_tot;++j)cout<<pig[i].card[j]<<" \n"[j==pig[i].card_tot];
	cout<<"\n";
}
void Ett(){
	int x=1;//当前回合决策猪 
	if(!fz_tot)ed=1;
	while(!ed){
		get_card(x);get_card(x);//回合摸牌阶段 
//		debug();
//		for(int i=1;i<=3;++i)cout<<pig[i].hp<<" \n"[i==3];
		int K_cnt=0;
		for(int i=1;i<=pig[x].card_tot;++i){
			if(ed)return ;
			if(pig[x].die)break;
			if(pig[x].card[i]=='E'||pig[x].card[i]=='J'||pig[x].card[i]=='D')continue;
			if(pig[x].card[i]=='P'){
				if(pig[x].hp!=4){
					pig[x].hp++;
					pig[x].card[i]='E';
				}
				continue;
			}
			if(pig[x].card[i]=='K'){
				if(K_cnt<1||pig[x].zgln){
					int target=pig[x].nxt;
					if((pig[x].cst=="MP"&&((pig[target].jump&&pig[target].cst=="FP"))||(pig[target].sim&&pig[target].jump==0))){
						pig[x].card[i]='E';
						pig[x].sim=0;
						use_K(x,target);
						K_cnt++;
					}
					if(pig[x].cst=="FP"&&((pig[target].jump&&pig[target].cst=="ZP")||pig[target].cst=="MP")){
						pig[x].jump=1;
						pig[x].sim=0;
						pig[x].card[i]='E';
						use_K(x,target);
						K_cnt++;
					}
					if(pig[x].cst=="ZP"&&pig[target].jump&&pig[target].cst=="FP"){
						pig[x].jump=1;
						pig[x].sim=0;
						pig[x].card[i]='E';
						use_K(x,target);
						K_cnt++;
					}
				}
				if(ed)return ;
				continue;
			}
			if(pig[x].card[i]=='F'){//duel
				if(pig[x].cst=="FP"){//have the chance of juedou MP!!
					pig[x].jump=1;//跳反
					pig[x].sim=0;
					pig[x].card[i]='E';
					jd(x,1);
					i=0;//发牌后可能激活前面的牌 
					if(ed)return ;
					continue;
				}
				else{
					int bdy=pig[x].nxt;
					while(bdy!=x){
							if( (pig[x].cst=="MP"&&((pig[bdy].jump&&pig[bdy].cst=="FP")||(pig[bdy].sim&&pig[bdy].jump==0)))
							||  (pig[x].cst=="ZP"&&pig[bdy].jump&&pig[bdy].cst=="FP") )
							{
								pig[x].jump=1;//跳忠 (1没事)
								pig[x].sim=0;
								pig[x].card[i]='E';
								jd(x,bdy);
								i=0;//发牌后可能激活前面的牌 
								if(ed)return ;
								break;
							}
						bdy=pig[bdy].nxt;
					}
				}
				continue;
			}
			if(pig[x].card[i]=='N'){//South pig in=vade
				pig[x].card[i]='E';
				nzrq(x);
				i=0;//发牌后可能激活前面的牌 
				if(ed)return ;
				continue;
			}
 			if(pig[x].card[i]=='W'){//Ten thousand arrows shot at once. 
				pig[x].card[i]='E';
 				wjqf(x);
				i=0;//发牌后可能激活前面的牌 
				if(ed)return ;
				continue;
			}
			if(pig[x].card[i]=='Z'){
				pig[x].zgln=1;
				pig[x].card[i]='E';
				i=0;
			} 
		}
		x=pig[x].nxt;
//		if((clock()-t)/CLOCKS_PER_SEC>1)break;
	}
}
void Sa(){
	if(ed==1)cout<<"MP\n";
	else cout<<"FP\n";
	for(int i=1;i<=n;++i){
		if(pig[i].die)cout<<"DEAD\n";
		else{
			for(int j=1;j<=pig[i].card_tot;++j)if(pig[i].card[j]!='E')cout<<pig[i].card[j]<<" ";
			cout<<"\n";
		}
	}
}
int main(){
//	ios::sync_with_stdio(0),cin.tie(0);
	t=clock();
	init();
	Ett();//Enter the turn
	Sa();//settle accounts 清算
	return 0;
}
/*
6 15
MP K W Z Z
FP J Z J K
ZP J W K D
ZP N P K P
ZP J P F J
ZP J Z K J
Z P D J D K W F F Z N J F F J
*/
//
posted @ 2024-08-02 18:48  余亦宸  阅读(68)  评论(1)    收藏  举报