题解 P2482 【[SDOI2010]猪国杀】

先无良宣传一下博客 \(wwwwww\)
文章列表 - 地灵殿 - 洛谷博客


坑点都被楼上的 \(Dalao\) 整理得差不多了 ,
我也没有赘述的必要了 = =

在这里分享一下自己做此题的一些技巧:


  1. 先写大纲 :

    像这种大模拟 , 一般是不需要 脑子 思维技巧 的
    只需要按照题意模拟即可
    这时候要格外注意细节

    所以推荐,在做题之前, 先写一份 伪代码
    在写伪代码过程中 ,

    1. 整理好大致思路
    2. 用注释的形式, 记录 坑点 和 疑问

    确保伪代码无误后 , 再去写 真代码

  2. \(string\)类 函数:

    其实对于\(string\),一开始我是拒绝的
    但是发现 \(find\) , \(erase\) , \(replace\) 的帅气酷炫之后
    \(string\) 世界一位 ! ! !

    在使用手牌的时候 ,
    可以使用 \(find\)\(erase\) 进行结合 :
    使用 \(find\) 判断手牌中有无此牌
    使用 \(erase\) 来删除手牌中的这张牌
    可以十分方便地完成指定的操作

    部分代码如下:

    bool use_ca(int so,string card)
    {
        int po=-1;
        po=p[so].ca.find(card);
        if(po==-1) return 0;
        p[so].ca.erase(po,1);
        return 1;
    }
    
  3. 关于缩进:

    像这种码量如此鬼畜的代码 ,
    代码 长几行短几行 其实无所谓了 = =
    可读性才是最重要的
    为了一时的压行,破坏观看体验
    不仅会很难受 ,
    还会出意想不到的bug = =

    就像某个 \(DD\) 一样:

    if(now_ca=="P" && p[now].bl<4) {p[now].ca.erase(i,1); ca_use=1; p[now].bl++;}
    if(now_ca=="Z") {p[now].ca.erase(i,1); ca_use=1; p[now].bo=1;}
    if(now_ca=="N") {p[now].ca.erase(i,1); ca_use=1; nanman(now);}
    if(now_ca=="W") {p[now].ca.erase(i,1); ca_use=1; wanjian(now);}
    if(now_ca=="F") {int ta=find_duel(now);if(ta==-1) continue;p[now].ca.erase(i,1); ca_use=1;if(judge_duel(now,ta)) duel(now,ta);}
    

    就因为鬼畜的压行 , 多调了 \(2h+\) = =



伪代码 (大纲):

猪国杀
目录:

主函数
备注
变量列表
子函数列表








主函数:
int main()
{
	输入()
	while(1)
  	  {
  		bool  判断是否用过杀=0;
		bool 使用了牌=0;
		摸牌(当前猪)x2;
		while(1)
		  {
		  	int i=0(牌指针)
		    For(i=所有牌,初值为0)
  		      {
  		  	    string 当前牌;
			    当前牌+=手牌[i];
			    If(桃 && 血量<4)
  		      手牌.earse(i,1),使用了牌,血量+1;
                if(诸葛连弩)
                  手牌.earse(i,1),使用了牌,装备; 
			    if(南蛮入侵||万箭齐发)
  			      手牌.earse(i,1),使用了牌,当前牌(使用猪);
			    if(决斗)
      		      {
					int 决斗对象=决斗能否生效(当前猪);
					if(决斗对象==-1)
					  continue; 
      		      	手牌.earse(i,1),使用了牌;
				    if(决斗是否生效(使用猪,被使用猪))
			          决斗(当前猪,决斗对象); 
		          }
			    if(能攻击(当前猪,下一猪) && 杀)
  			  	  if(没有使用杀||诸葛连弩) 
      			    手牌.earse(i,1),使用了牌,杀(当前猪,下一猪),使用了杀;
      	       if(使用了牌)
			     break;
			  }
		    if(!使用了牌) break;
			if(当前猪:血<=0) break;
			i=0; 
		  }
     	当前猪=下一猪; 
      }
}





备注:
1.	队列存手牌,牌堆(手牌用数组模拟,牌堆用stl)
2.	链表存猪的顺序(链表指向下一猪)
3.  0主公,1忠臣,2反贼 


变量列表:
1.	结构体存某一猪
{
	int型 血量;
	int型 身份;(0主公,1忠臣,2反贼 ) 
	int型 倾向(0表示没有跳 1确定倾向主公,2确定倾向反贼,3倾向类反贼)
	string型 手牌;
	bool型 是否装备诸葛连弩;
}
2 int型二维数组,链表存上一猪,下一猪;
3 bool型变量,判断主公是否死亡,初始为1;
4 int型变量,记录存活的反贼个数; 



子函数列表:
1.	Void 输入
{
	For(i=人数)
      {
	    身份,摸牌(i)x4;
		记录身份;
		if(阵营为主公)
		  倾向=主公; 
		血量=4;
		If(反贼) 反贼存活数+1;
	  }
    for(i=牌堆牌数)
   	  输入,压入牌堆队列;
}
2.	Void 摸牌(猪编号)
{
	string 摸得牌;
	摸得牌=牌堆.front();
	if(不是最后一张牌) 
	  {
		牌堆牌数--; 
		牌堆.pop();
	  }
    此猪手牌+摸得牌;
	return ;
}
3.void 杀(使用猪编号,被使用猪编号)
{
	if(被使用猪倾向为反贼) 使用猪倾向=主公;
	if(被使用猪倾向主公) 使用猪倾向=反贼;
    If(!使用某张牌(被使用猪,闪)) 
  	  被使用猪:血量-1; 
	if(被使用猪:血量<=0)
  	  濒死(使用猪,被使用猪);
}
4. void 濒死(使用猪,被使用猪)
{ 
	while(被使用猪:血量<=0) 
      {
      	if(使用某张牌(被使用猪,桃))  被使用猪:血量+1;
	    else break; 
	  }
	if(被使用猪:血量<=0)
      {
		if(被使用猪为反贼) 
		  {
            反贼数-1;
			游戏结束(); 
			摸牌(使用猪)x3; 
		  }
        if(被使用猪为忠臣 && 使用猪为主公)
     主公手牌="",装备牌弃除;
		if(被使用猪为主公)
          {
		    主公死亡;
		    游戏结束();
		  }
		被指用猪的上一猪,链表指向被使用猪的下一猪; 
	  }
}
5.void 游戏结束()
{
	if(主猪死亡 || 反贼数==0)
  	  {
  	  	输出;
		exit(0);
	  }
	return ;
}
6.void 南蛮入侵(使用猪)
{
	for(i=存活所有猪)
  	  {
      	bool 是否被无懈; 
     	if(i猪跳身份)
		  for(j=以使用猪为起点逆时针遍历猪)
   			if(j猪阵营=i猪倾向)
			  if(使用某张牌(j猪,无懈可击))
   			{
				  j猪倾向=i猪倾向;
				  if(无懈(j猪))
 					是否被无懈=真, break;
				}
		if(被无懈)continue;
		if(!使用某张牌(i猪,杀))
		  {
			血-1; 
			if(i猪为主公&&使用猪无倾向) 使用猪倾向类反贼; 
		  }
       	If(i猪血<=0) 濒死(使用猪,i猪);
	  }
}
7.万箭齐发(使用猪)
{
	for(i=存活所有猪)
  	  {
      	bool 是否被无懈; 
     	if(i猪跳身份)
		  for(j=以使用猪为起点逆时针遍历猪)
   			if(j猪阵营=i猪倾向)
			  if(使用某张牌(j猪,无懈可击))
   			{
				  j猪倾向=i猪倾向;
				  if(无懈(j猪))
 					是否被无懈=真, break;
				}
		if(被无懈)continue;
		if(!使用某张牌(i猪,闪))
		  {
			血-1; 
			if(i猪为主公&&使用猪无倾向) 使用猪倾向类反贼; 
		  }
       	if(i猪血<=0) 濒死(使用猪,i猪);
	  }
}
8 .bool 无懈可击(使用猪)
{
	bool 是否被抵消; 
	for(i=逆时针遍历从使用猪之后的猪)
	  if(i猪与使用猪相反阵营)
	    if(使用某张牌(i猪,无懈可击))
	      {
	        i猪倾向=(!使用猪倾向)
		    if(无懈可击(i猪)) 
		      {
			    是否被抵消=真;
			    break;
			  }
	      }
	if(被抵消) return 0;
	return 1; 
}
9 .void 决斗(使用猪,被使用猪)
{
	if(被使用猪身份为忠 && 使用猪为主)
	  {
	  	被使用猪:血-1;
		if(被使用猪:血<=0)
		  濒死(使用猪,被使用猪)
		return ;
	  }
	if(使用某张牌(被使用猪,杀))
	  决斗(被使用猪,使用猪);
	else
	  {
	  	被使用猪:血-1;
		if(被使用猪:血<=0)
		  濒死(使用猪,被使用猪) 
		return ; 
	  }
}
10 .bool 判断是否可攻击(猪1,猪2)
{
	if(猪1==主猪 && 猪2阵营!=猪1阵营)
	  return 1;
	if(猪1==忠猪 && 猪2阵营==反猪)
	  return 1;
	if(猪1==反猪 && 猪2阵营!=猪1阵营)
	  return 1;
	return 0; 
}
11 .int 找决斗目标(使用猪)
{
	int 被使用猪=-1;
	if(使用猪为反猪)
	  {
	  	被使用猪=主猪; 
		使用猪倾向=反猪;
	  }
	if(使用猪为主猪)
	  {
	  	for(i=逆时针遍历所有猪)
		  if(i猪跳反/类反)
		    被使用猪=该猪,break;
	  }
	if(使用猪为忠猪)
	  {
	  	for(i=逆时针遍历所有猪)
		  if(i猪跳反)
		    {
		      被使用猪=该猪,break;
			  使用猪倾向=主猪; 
			}
	  }
	return 被使用猪;
}
12 .bool 决斗是否生效(使用猪,被使用猪)
{
	bool 是否被无懈;
	if(被使用猪跳身份)
	  For(j=逆时针遍历从使用猪之后的猪)
   	    If(j猪阵营=被使用猪阵营)
		  if(使用某张牌(j猪,无懈可击))
   	        {
		   	   j猪倾向=被使用猪倾向;
		   	   if(无懈(j猪))
 			    是否被无懈=真, break;
		    }
	if(被无懈) return 0;
	return 1; 
} 
13. bool 使用某张牌(使用猪,某张牌)
{
	int 牌位置=-1; 
	牌位置=使用猪手牌.find(某张牌);
	if(牌位置==-1)
	  return 0;
	手牌.earse(牌位置,1);
	return 1; 
}

代码:


//人生第一黑 
//大纲,已经写的非常详细了 
//请恕我不写注释= = 
#include<iostream>
#include<cstdlib>
#include<queue>
#include<string>
using namespace std;
//=============变量=============================
int pigs_count,pile_count;
struct each_pig
{
	int bl;
	int id;
	int gr;
	bool bo;
	string ca;
}p[15];
int ne_p[15];
int pre_p[15];
bool dead_MP=0;
int alive_FP=0;
int now=1; 
queue <string> pile;
//============子函数列表===========================
void read();
void get_ca(int);
void attack(int,int);
void dying(int,int);
void game_end();
void nanman(int);
void wanjian(int);
bool wuxie(int);
void duel(int,int);
bool judge_attack(int,int);
bool judge_duel(int,int);
int find_duel(int);
bool use_ca(int,string);
//==============主函数================================
int main()
{
	read();
	while(1)
	{
	  bool attack_use=0;
	  get_ca(now);
	  get_ca(now);
	  while(1)
	  {
	  	bool ca_use=0;
	  	int i=0;
	  	for(i;p[now].ca[i];i++)
	  	{
	  	  string now_ca;
	  	  now_ca+=p[now].ca[i];
	  	  if(now_ca=="P" && p[now].bl<4)
	  	    {p[now].ca.erase(i,1); ca_use=1; p[now].bl++;}
	  	  if(now_ca=="Z")
	  	  	{p[now].ca.erase(i,1); ca_use=1; p[now].bo=1;}
		  if(now_ca=="N")
			{p[now].ca.erase(i,1); ca_use=1; nanman(now);}
		  if(now_ca=="W")
			{p[now].ca.erase(i,1); ca_use=1; wanjian(now);}
		  if(now_ca=="F")
			{
			  int ta=find_duel(now);
			  if(ta==-1) continue;
			  p[now].ca.erase(i,1); ca_use=1;
			  if(judge_duel(now,ta)) duel(now,ta);
			}
		  if(now_ca=="K" && judge_attack(now,ne_p[now]))
		    if(!attack_use || p[now].bo)
			{
			  p[now].ca.erase(i,1);
			  ca_use=1;attack_use=1;
			  attack(now,ne_p[now]);
			}
		  if(ca_use) break;
		}
		if(!ca_use) break;
		if(p[now].bl<=0) break;
		i=0;
	  }
	  now=ne_p[now];
	}
}
//==============子函数================================ 
void read()
{
	cin>>pigs_count>>pile_count;
	for(int i=1;i<=pigs_count;i++)
	  {
	  	if(i==1) pre_p[i]=pigs_count;
	  	else  pre_p[i]=i-1;
	  	if(i==pigs_count) ne_p[i]=1;
	  	else ne_p[i]=i+1;
	  }
	for(int i=1;i<=pigs_count;i++)
	  {
	  	string shenfen;
	  	cin>>shenfen;
	  	p[i].bl=4;
	  	if(shenfen=="MP") p[i].id=0,p[i].gr=1;
	  	if(shenfen=="ZP") p[i].id=1;
	  	if(shenfen=="FP") p[i].id=2,alive_FP++;
		for(int j=1;j<=4;j++)
		  {
		  	string cin_ca;
		  	cin>>cin_ca;
		  	p[i].ca+=cin_ca;
		  }
	  }
	for(int i=1;i<=pile_count;i++)
	  {
	  	string cin_ca;
	  	cin>>cin_ca;
	  	pile.push(cin_ca);
	  }
}
void get_ca(int so)
{
	string cin_ca;
	cin_ca=pile.front();
	if(pile_count>1)
	  {
	  	pile_count--;
	  	pile.pop();
	  }
	p[so].ca+=cin_ca;
	return ;
}
void attack(int so,int ta)
{
	if(p[ta].gr==2) p[so].gr=1;
	if(p[ta].gr==1) p[so].gr=2;
	if(!use_ca(ta,"D"))
	  p[ta].bl--;
	if(p[ta].bl<=0)
	  dying(so,ta);
}
void dying(int so,int ta)
{
	while(p[ta].bl<=0)
	  {
	  	if(use_ca(ta,"P")) p[ta].bl++;
	  	else  break;
	  }
	if(p[ta].bl<=0)
	  {
	  	if(p[ta].id==2)
	  	  {
	  	  	alive_FP--;
	  	  	game_end();
	  	  	get_ca(so);
	  	  	get_ca(so);
	  	  	get_ca(so);
		  }
		if(p[ta].id==1 && p[so].id==0)
		  {p[so].ca.clear(),p[so].bo=0;}
		if(p[ta].id==0)
		  {
		  	dead_MP=1;
		  	game_end();
		  }
		ne_p[pre_p[ta]]=ne_p[ta];
		pre_p[ne_p[ta]]=pre_p[ta];
	  }
}
void game_end()
{
	if(dead_MP || !alive_FP)
	  {
	  	if(dead_MP) cout<<"FP"<<endl;
	  	else cout<<"MP"<<endl;
	  	for(int i=1;i<=pigs_count;i++)
	  	  {
	  	  	if(p[i].bl<=0) cout<<"DEAD"<<endl;
	  	  	else
	  	  	  {
				for(int j=0;p[i].ca[j];j++)
	  	  	      cout<<p[i].ca[j]<<" ";
	  	  	    cout<<endl;
	  	  	  }
		  }
		exit(0);
	  }
	return ;
}
void nanman(int so)
{
	for(int i=ne_p[so];i!=so;i=ne_p[i])
	  {
	  	bool wuxie_use=0;
	  	if(p[i].gr && p[i].gr!=3)
	  	  {
	  	  	int vi[15]={0};
	  	  	for(int j=so;j;j=ne_p[j])
	  	  	  if(vi[j]++) break;
	  	  	  else 
				if(p[j].id==p[i].gr || p[j].gr==p[i].gr)
				  if(use_ca(j,"J"))
				    {
				      p[j].gr=p[i].gr;
				      if(wuxie(j))
				        {
				          wuxie_use=1;
				          break;
						}
					}
		  }
		if(wuxie_use) continue;
		if(!use_ca(i,"K"))
		  {
		  	p[i].bl--;
		  	if(p[i].id==0 && !p[so].gr)
		  	  p[so].gr=3;
		  }
		if(p[i].bl<=0) dying(so,i);
	  }
}
void wanjian(int so)
{
	for(int i=ne_p[so];i!=so;i=ne_p[i])
	  {
	  	bool wuxie_use=0;
	  	if(p[i].gr && p[i].gr!=3)
	  	  {
	  	  	int vi[15]={0};
	  	  	for(int j=so;j;j=ne_p[j])
	  	  	  if(vi[j]++) break;
	  	  	  else 
				if(p[j].id==p[i].gr || p[j].gr==p[i].gr) 
				  if(use_ca(j,"J"))
				    {
				      p[j].gr=p[i].gr;
				      if(wuxie(j))
				        {
				          wuxie_use=1;
				          break;
						}
					}
		  }
		if(wuxie_use) continue;
		if(!use_ca(i,"D"))
		  {
		  	p[i].bl--;
		  	if(p[i].id==0 && !p[so].gr)
		  	  p[so].gr=3;
		  }
		if(p[i].bl<=0) dying(so,i);
	  }
}
bool wuxie(int so)
{
	bool wuxie_use=0;
	int vi[15]={0};
	for(int i=so;i;i=ne_p[i])
	  if(vi[i]++)
	    break;
	  else 
	    if(judge_attack(i,so))
	      if(use_ca(i,"J"))
	        {
	      	  p[i].gr=p[so].gr==1?2:1;
	      	  if(wuxie(i))
	      	    {
	      	      wuxie_use=1;
	      	  	  break;
			    }
		    }
	if(wuxie_use) 
	  return 0;
	return 1;
}
void duel(int so,int ta)
{
	if(p[ta].id==1 && p[so].id==0)
	  {
	  	p[ta].bl--;
	  	if(p[ta].bl<=0)
	  	  dying(so,ta);
	  	return ;
	  }
	if(use_ca(ta,"K")) 
	  duel(ta,so);
	else
	  {
	  	p[ta].bl--;
	  	if(p[ta].bl<=0)
	  	  dying(so,ta);
	  	return ;
	  }
}
bool judge_attack(int so,int ta)
{
	if(p[so].id==0 && p[so].gr!=p[ta].gr && p[ta].gr) return 1;
	if(p[so].id==1 && p[ta].gr==2) return 1;
	if(p[so].id==2 && p[so].id!=p[ta].gr && p[ta].gr && p[ta].gr!=3) return 1;
	return 0;
}
int find_duel(int so)
{
	int ta=-1;
	if(p[so].id==2)
	  {
	  	ta=1;
	  	p[so].gr=2;
	  }
	else
	  for(int i=ne_p[so];i!=so;i=ne_p[i])
	  	if(p[i].gr==2 || (p[i].gr==3 && p[so].id==0))
	  	  {
	  	  	p[so].gr=1;
	  	    ta=i;
	  	    break;
		  }
	return ta;
}
bool judge_duel(int so,int ta)
{
	bool wuxie_use=0;
	if(p[ta].gr!=0 && p[ta].gr!=3)
	  for(int i=ne_p[so];i!=so;i=ne_p[i]) 
	    if(p[i].id==p[ta].gr || p[ta].gr==p[i].gr)
	      if(use_ca(i,"J"))
			{
			  p[i].gr=p[ta].gr;
			  if(wuxie(i))
				{
				  wuxie_use=1;
				  break;
				}
			}
	if(wuxie_use) return 0;
	return 1;
}
bool use_ca(int so,string card)
{
	int po=-1;
	po=p[so].ca.find(card);
	if(po==-1)
	  return 0;
	p[so].ca.erase(po,1);
	return 1;
}

另外 , 该代码是 \(Baka\) 阿空的早期作品 ,
码风极丑 , 语法混乱 , 各位凑活着看 = =

posted @ 2019-09-03 22:43  Luckyblock  阅读(257)  评论(2)    收藏  举报