洛谷P2482 [SDOI2010]猪国杀

Posted lonlyn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P2482 [SDOI2010]猪国杀相关的知识,希望对你有一定的参考价值。

题目:https://www.luogu.org/problemnew/show/P2482

题目描述

《猪国杀》是一种多猪牌类回合制游戏,一共有三种角色:主猪,忠猪,反猪。每局游戏主猪有且只有一只,忠猪和反猪可以有多只,每只猪扮演一种角色。

游戏目的:

主猪(MP):自己存活的情况下消灭所有的反猪。

忠猪(ZP):不惜一切保护主猪,胜利条件与主猪相同。

反猪(AP):杀死主猪。

游戏过程:

游戏开始时候,每个玩家手里都会有4张牌,且体力上限和初始体力都是4。

开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从1,2,3..n,1..的顺序)依次行动。

每个玩家自己的回合可以分为4个阶段:

◎摸牌阶段:从牌堆顶部摸两张牌,依次放到手牌的最右边;

◎出牌阶段:你可以使用0张到任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。当然,要满足如下规则:

1.如果没有猪哥连弩,每个出牌阶段只能使用一次“杀”来攻击;

2.任何牌被使用后被弃置(武器是装备上);

被弃置的牌以后都不能再用,即与游戏无关;

各种牌介绍:

每张手牌用一个字母表示,字母代表牌的种类。

◎基本牌:

『桃(P)』:在自己的回合内,如果自己的体力值不等于体力上限,那么使用一个桃可以为自己补充一点体力,否则不能使用桃;桃只能对自己使用;在自己的回合外,如果自己的血变为0或者更低,那么也可以使用;

『杀(K)』:在自己的回合内,对攻击范围内除自己以外的一名角色使用。如果没有被『闪』抵消,则造成1点伤害。无论有无武器,杀的攻击范围都是1;

『闪(D)』:当你受到杀的攻击时,可以弃置一张闪来抵消杀的效果;

◎锦囊牌:

『决斗(F)』:出牌阶段,对除自己以外任意一名角色使用,由目标角色先开始,自己和目标角色轮流弃置一张杀,首先没有杀可弃的一方受到1点伤害,另一方视为此伤害的来源;

『南猪入侵(N)』:出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置一张杀,否则受到1点伤害;

『万箭齐发(W)』:和南猪入侵类似,不过要弃置的不是杀而是闪;

『无懈可击(J)』:在目标锦囊生效前抵消其效果。每次有一张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会;

效果:用于决斗时,决斗无效并弃置;用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对一个角色产生效果);用于无懈可击时,成为目标的无懈可击被无效。

◎装备牌:

『猪哥连弩(Z)』:武器,攻击范围1,出牌阶段你可以使用任意张杀;

同一时刻最多只能装一个武器;如果先前已经有了一把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器;

特殊事件及概念解释:

◎伤害来源:杀、南猪入侵、万箭齐发的伤害来源均是使用该牌的猪,决斗的伤害来源如上;

◎距离:两只猪的距离定义为沿着逆时针方向间隔的猪数+1。即初始时1和2的距离为1,但是2和1的距离就是n-1。注意一个角色的死亡会导致一些猪距离的改变;

◎玩家死亡:如果该玩家的体力降到0或者更低,并且自己手中没有足够的桃使得自己的体力值回到1,那么就死亡了,死亡后所有的牌(装备区,手牌区)被弃置;

◎奖励与惩罚:反猪死亡时,最后一个伤害来源处(即使是反猪)立即摸三张牌。忠猪死亡时,如果最后一个伤害来源是主猪,那么主猪所有装备牌、手牌被弃置;

◎注意,一旦达成胜利条件,游戏立刻结束,因此即使会摸3张牌或者还有牌可以用也不用执行了。

现在,我们已经知道每只猪的角色、手牌,还有牌堆初始情况,并且假设每个角色会按照如下的行为准则进行游戏,你需要做的就是告诉小猪iPig最后的结果。

几种行为:

◎献殷勤:使用无懈可击挡下南猪入侵、万箭齐发、决斗;使用无懈可击抵消表敌意;

◎表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤;

◎跳忠:即通过行动表示自己是忠猪。跳忠行动就是对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意;

◎跳反:即通过行动表示自己是反猪。跳反行动就是对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤;

忠猪不会跳反,反猪也不会跳忠;不管是忠猪还是反猪,能够跳必然跳;

行动准则:

共性:每个角色如果手里有桃且生命值未满,那么必然吃掉;有南猪入侵、万箭齐发、必然使用;有装备必然装上;受到杀时,有闪必然弃置;响应南猪入侵或者万箭齐发时候,有杀/闪必然弃置;不会对未表明身份的猪献殷勤(包括自己);

特性:

◎主猪:主猪会认为没有跳身份,且用南猪入侵/万箭齐发对自己造成伤害的猪是“类反猪”(没伤害到不算,注意“类反猪”并没有表明身份),如果之后跳了,那么主猪会重新认识这只猪;对于每种表敌意的方式,对逆时针方向能够执行到的第一只“类反猪”或者已跳反猪表;如果没有,那么就不表敌意;决斗时会不遗余力弃置杀;如果能对已经跳忠的猪或自己献殷勤,那么一定献;如果能够对已经跳反的猪表敌意,那么一定表;

◎忠猪:对于每种表敌意的方式,对逆时针方向能够执行到的第一只已经跳反的猪表,如果没有,那么就不表敌意;决斗时,如果对方是主猪,那么不会弃置杀,否则,会不遗余力弃置杀;如果有机会对主猪或者已经跳忠的猪献殷勤,那么一定献;

◎反猪:对于每种表敌意的方式,如果有机会则对主猪表,否则,对逆时针方向能够执行到的第一只已经跳忠的猪表,如果没有,那么就不表敌意;决斗时会不遗余力弃置杀;如果有机会对已经跳反的猪献殷勤,那么一定献;

限于iPig只会用P++语言写A + B,他请你用Pigcal(Pascal)、P(C)或P++(C++)语言来帮他预测最后的结果。

输入输出格式

输入格式:

 

输入文件第一行包含两个正整数n(2 <= n <= 5) (这地方数据范围错误应该开到至少20吧)和m( m <= 2000),分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。(实际上,牌不够用时要一直摸最后一张)

接下来n行,每行5个字符串,依次表示对第i只猪的角色和初始4张手牌描述。编号为1的肯定是主猪。

再接下来一行,一共m个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。

所有的相邻的两个字符串都严格用1个空格隔开,行尾没有多余空格。

 

输出格式:

 

输出数据第一行包含一个字符串代表游戏结果。如果是主猪胜利,那么输出“MP”,否则输出“FP”。数据保证游戏总会结束。

接下来n行,第i行是对第i只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用一个空格隔开,行末尾没有多余空格。如果这只猪已阵亡,那么只要输出“DEAD”即可。注意如果要输出手牌而没有手牌的话,那么只需输出一个空行。

 

输入输出样例

输入样例#1: 
3 10
MP D D F F
ZP N N N D
FP J J J J
F F D D J J F F K D
输出样例#1: 
FP
DEAD
DEAD
J J J J J J D

说明

样例1说明:第一回合主猪没有目标可以表敌意;接下来忠猪使用了3张南猪入侵,主猪掉了3点体力,并认为该角色为类反猪,3号角色尽管手里有无懈可击,但是因为自己未表明身份,所以同样不能对自己用,乖乖掉3点体力;下一回合反猪无牌可出;接下来主猪对着类反猪爆发,使用4张决斗,忠猪死亡,结果主猪弃掉所有牌;下来反猪摸到一张杀直接杀死主猪获胜。

数据说明:一共20组测试数据,每个点5分。10%的数据没有锦囊牌,另外20%的数据没有无懈可击

 

解析

这道题我真的没啥话可说了。

首先,题面有错误。

①玩家不止5个,尽量开大点吧。

②牌可能不够用,要一直摸最后一张。

其次,这道题考察代码能力和读题水平非常高。

下面总结几个坑点(自己+其他大佬):

①弃牌要弃装备。

②如果一个人打出无懈可击,则从他开始询问是否无懈无懈可击。

③一个人每打出一张牌,要重新从他的第一张手牌判断是否可以打出,因为aoe技能会导致一些人跳身份,决斗或者杀会影响距离,诸葛会使得可以用前面的杀。

④对他人决斗可能导致自己死亡,要及时终止出牌阶段。

⑤题目中的距离与平常意义上的距离不一样,是逆时针旋转的距离。

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

⑦出锦囊的人是有可能无懈掉这个锦囊的。

⑧别人对你出决斗/aoe技能,你可能因自己没有亮身份而不使用无懈可击。

⑨无懈可击出了,身份就亮了。

⑩(个人的)判断决斗时,有三种情况,要用int不能用bool。

模拟的巅峰。

技术分享图片
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<queue>
  7 #include<vector>
  8 using namespace std;
  9 #define maxn 20100
 10 struct pig{
 11     bool rebel,sim_rebel;
 12     bool jumped;
 13     int hp;
 14     bool zhuge;
 15     int hands;
 16     char hand[maxn];
 17     bool used[maxn];
 18 }player[30];
 19 int n,m;
 20 char restring[maxn];
 21 int rebel_tot;
 22 int now_paidui=1; 
 23 char paidui[maxn];
 24 int gameover=0;
 25 char rech;
 26 void renew_hand(int p){
 27     int now_h=0,mac=player[p].hands;
 28     for (int i=1;i<=mac;++i){
 29         if (player[p].used[i]) continue;
 30         player[p].hand[++now_h]=player[p].hand[i];
 31         player[p].used[now_h]=false;
 32     }
 33     player[p].hands=now_h;
 34 }
 35 void get_card(int p,int js){
 36     if (gameover!=0) return;
 37     for (int i=1;i<=js;++i){
 38         player[p].hand[++player[p].hands]=paidui[now_paidui];
 39         player[p].used[player[p].hands]=false;
 40         now_paidui++;
 41         if (now_paidui==m+1) now_paidui=m;
 42     }
 43 }
 44 int get_dis(int a,int b){
 45     int ans=0;
 46     while (a!=b){
 47         ++a;
 48         if (a==n+1) a=1;
 49         if (player[a].hp) ++ans;
 50     }
 51     return ans;
 52 }
 53 bool useable(int p,char ch){
 54     for (int i=1;i<=player[p].hands;++i){
 55         if (player[p].used[i]) continue;
 56         if (player[p].hand[i]==ch){
 57             player[p].used[i]=true;
 58             return true;
 59         }        
 60     }
 61     return false;
 62 }
 63 bool missable(int p){
 64     return useable(p,D);
 65 }
 66 bool naiable(int p){
 67     return useable(p,P);
 68 }
 69 bool shaable(int p){
 70     return useable(p,K);
 71 }
 72 bool wuxieable(int p){
 73     if (useable(p,J)){
 74         player[p].jumped=true;
 75         return true;
 76     }
 77     return false;
 78 }
 79 void gg(int v,int u){
 80     if (v==1){
 81         gameover=2;
 82         return;
 83     }
 84     if (player[v].rebel){
 85         rebel_tot--;
 86         if (rebel_tot==0){
 87             gameover=1;
 88             return;
 89         }
 90         get_card(u,3);
 91         return;
 92     }
 93     if ((!player[v].rebel&&v!=1)&&(u==1)){
 94         player[u].hands=0;
 95         player[u].zhuge=false;
 96     }
 97 }
 98 void diaoxie(int v,int u){
 99     player[v].hp--;
100     if (player[v].hp==0){
101         if (naiable(v)) player[v].hp++;
102         else gg(v,u);
103     }
104 }
105 bool nilaia(int u,bool ident){
106     int now=u;
107     do{
108         if (player[now].hp&&player[now].rebel==ident){
109             if (wuxieable(now)){
110                 if (!nilaia(now,!ident)) return true;
111                 else return false;
112             }
113         }
114         now++;
115         if (now==n+1) now=1;
116     }while (now!=u);
117     return false;
118 }
119 bool gun(int v,int u){ //wuxiekeji
120     if (!player[v].jumped&&v!=1) return false;
121     if (nilaia(u,player[v].rebel)) return true;
122     return false;
123 }
124 bool killable(int p){
125     if (player[p].rebel){
126         if (get_dis(p,1)==1){
127             player[p].jumped=true;
128             if (!missable(1)) diaoxie(1,p);
129             return true;
130         }
131     }
132     if (p==1){
133         for (int i=2;i<=n;++i){
134             if (player[i].hp){
135                 if ((player[i].rebel&&player[i].jumped)||(player[i].sim_rebel&&!player[i].jumped)){
136                     if (get_dis(p,i)==1){
137                         if (!missable(i)) diaoxie(i,p);
138                         return true;
139                     }
140                 }
141             }
142         }
143     }else{
144         int now=p+1;
145         if (now==n+1) now=1;
146         while (now!=p){ 
147             if (player[now].hp<=0){
148                 now++;
149                 if (now==n+1) now=1;
150                 continue;
151             }
152             if ((player[now].rebel!=player[p].rebel)&&player[now].jumped){
153                 if (get_dis(p,now)==1){
154                     player[p].jumped=true;
155                     if (!missable(now)) diaoxie(now,p);
156                     return true;
157                 }
158             } 
159             now++;
160             if (now==n+1) now=1;
161         }
162     }
163     return false;
164 }
165 int duel_judge(int v,int u){
166     if ((!player[v].rebel&&v!=1)&&u==1) return 1;
167     if (gun(v,u)) return 2;
168     while (true){
169         if (!shaable(v)) return 1;
170         if (!shaable(u)) return 0;
171     }
172 }
173 bool duelable(int p){
174     if (player[p].rebel){
175         player[p].jumped=true;
176         int sid=duel_judge(1,p);
177         if (sid==1) diaoxie(1,p);
178         else if (sid==0) diaoxie(p,1);
179         return true;
180     }
181     if (p==1){
182         for (int i=2;i<=n;++i){
183             if (player[i].hp){
184                 if ((player[i].rebel&&player[i].jumped)||(player[i].sim_rebel&&!player[i].jumped)){
185                     int sid=duel_judge(i,p);
186                     if (sid==1) diaoxie(i,p);
187                     else if (sid==0) diaoxie(p,i);
188                     return true;
189                 }
190             }
191         }
192     }else{
193         int now=p+1;
194         if (now==n+1) now=1;
195         while (now!=p){
196             if (player[now].hp<=0){
197                 now++;
198                 if (now==n+1) now=1;
199                 continue;
200             }
201             if ((player[now].rebel!=player[p].rebel)&&player[now].jumped){
202                 player[p].jumped=true;
203                 int sid=duel_judge(now,p);
204                 if (sid==1) diaoxie(now,p);
205                 else if (sid==0) diaoxie(p,now);
206                 return true;
207             }
208             now++; 
209             if (now==n+1) now=1;
210         }
211     }
212     return false;
213 }
214 void cuo_ding(int p,int kinds){
215     if (gameover!=0) return;
216     int now=p+1;
217     if (now==n+1) now=1;
218     while (now!=p){
219         if (player[now].hp<=0){
220             now++;
221             if (now==n+1) now=1;
222             continue;
223         }
224         if (gun(now,p)){
225             now++;
226             if (now==n+1) now=1;
227             continue;
228         }
229         if (kinds==1){
230             if (!shaable(now)){
231                 if (now==1) player[p].sim_rebel=true;
232                 diaoxie(now,p);
233             }
234         }else{
235             if (!missable(now)){
236                 if (now==1) player[p].sim_rebel=true;
237                 diaoxie(now,p);
238             }
239         }
240         if (gameover!=0) return;
241         now++;
242         if (now==n+1) now=1;
243     }
244 }
245 void chupai(int p){
246     bool chusha=false;
247     for (int i=1;i<=player[p].hands;++i){
248         if (gameover!=0||player[p].hp<=0) return;
249         if (player[p].used[i]) continue;
250         if (player[p].hand[i]==P){
251             if (player[p].hp<4){
252                 player[p].hp++;
253                 player[p].used[i]=true;
254                 i=0;
255             }
256         }
257         else if (player[p].hand[i]==K&&(!chusha||player[p].zhuge)){
258             if (killable(p)){
259                 chusha=true;
260                 player[p].used[i]=true;
261                 i=0;
262             }
263         }
264         else if (player[p].hand[i]==F){
265             if (duelable(p)){
266                 player[p].used[i]=true;
267                 if (player[p].hp<=0) return;
268                 i=0;
269             }
270         }
271         else if (player[p].hand[i]==Z){
272             player[p].used[i]=true;
273             if (player[p].zhuge) continue;
274             player[p].zhuge=true;
275             i=0;
276         }
277         else if (player[p].hand[i]==N){
278             player[p].used[i]=true;
279             cuo_ding(p,1); //sha
280             i=0;
281         }
282         else if (player[p].hand[i]==W){
283             player[p].used[i]=true;
284             cuo_ding(p,2); //shan
285             i=0;
286         }
287         if (gameover!=0) return;
288     }
289 }
290 void start_your_performance(int p){
291     if (gameover!=0) return;
292     renew_hand(p);
293     get_card(p,2);
294     chupai(p);
295 }
296 void zai_lai_yi_ju(){
297     for (int i=1;i<=n;++i){
298         if (player[i].hp>=1&&gameover==0){
299             start_your_performance(i);
300         }
301     }
302 }
303 void da_ji_da_li_jin_wan_chi_ji(){
304     if (gameover==1) printf("MP\n");
305     else printf("FP\n");
306     for (int i=1;i<=n;++i){
307         if (player[i].hp<=0){
308             printf("DEAD\n");
309             continue;
310         }
311         renew_hand(i);
312         for (int j=1;j<=player[i].hands;++j){
313             printf("%c ",player[i].hand[j]);
314         }
315         printf("\n");
316     }
317 }
318 int main(){
319     scanf("%d%d",&n,&m);
320     for (int i=1;i<=n;++i){
321         memset(player[i].hand,0,sizeof(player[i].hand));
322         player[i].hands=0;
323         player[i].hp=4;
324         player[i].jumped=player[i].rebel=player[i].sim_rebel=player[i].zhuge=false;
325         memset(player[i].used,false,sizeof(player[i].used));
326     }
327     for (int i=1;i<=n;++i){
328         cin>>rech;
329         while (rech<A||rech>Z) cin>>rech,cout<<rech<<endl;
330         if (rech==F){
331             ++rebel_tot;
332             player[i].rebel=true;
333         }
334         cin>>rech;
335         for (int j=1;j<=4;++j){
336             cin>>rech;
337             while (rech<A||rech>Z) cin>>rech;
338             player[i].hand[j]=rech;
339         }
340         player[i].hands=4;
341         player[i].hp=4;
342     }
343     for (int i=1;i<=m;++i){
344         cin>>rech;
345         while (rech<A||rech>Z) cin>>rech;
346         paidui[i]=rech;
347     }
348     while (gameover==0){
349         zai_lai_yi_ju();
350     }
351     da_ji_da_li_jin_wan_chi_ji();
352     return 0;
353 }
gg

 

以上是关于洛谷P2482 [SDOI2010]猪国杀的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P2482 [SDOI2010]猪国杀

洛谷P2482 猪国杀

[SDOI2010]猪国杀

[SDOI2010]猪国杀

Luogu2482 [SDOI2010]猪国杀

[Sdoi2010]猪国杀