zoukankan      html  css  js  c++  java
  • 洛谷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
    ");
    305     else printf("FP
    ");
    306     for (int i=1;i<=n;++i){
    307         if (player[i].hp<=0){
    308             printf("DEAD
    ");
    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("
    ");
    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
  • 相关阅读:
    《游戏引擎架构》笔记十二
    《游戏引擎架构》笔记十一
    《游戏引擎架构》笔记十
    《游戏引擎架构》笔记九
    《游戏引擎架构》笔记八
    《游戏引擎架构》笔记七
    2000行代码实现软渲染引擎
    C++ 构造函数或析构函数调用虚函数
    C++ protected访问权限思考
    堆排序
  • 原文地址:https://www.cnblogs.com/gjc1124646822/p/8168863.html
Copyright © 2011-2022 走看看