• [Sdoi2010]猪国杀


    [Sdoi2010]猪国杀

    题目

    我能说太长了不想粘吗QAQ——自己的幕布(比博客可读多了QAQ)

    《猪国杀》是一种多猪牌类回合制游戏,一共有三种角色:主猪,忠猪,反猪。

    每局游戏主猪有且只有一只,忠猪和反猪可以有多只,每只猪扮演一种角色。
    游戏目的
    主猪(MP):自己存活的情况下消灭所有的反猪。
    忠猪(ZP):不惜一切保护主猪,胜利条件与主猪相同。
    反猪(AP):杀死主猪。
    游戏过程
    游戏开始时候,每个玩家手里都会有 4 张牌,且体力上限和初始体力都是 4 。
    开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1, 2, 3...n, 1... 的顺序)依次行动。
    每个玩家自己的回合可以分为 4 个阶段
    摸牌阶段
    从牌堆顶部摸两张牌,依次放到手牌的最右边。
    出牌阶段
    你可以使用 0 张到任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。
    当然,要满足如下规则
    如果没有猪哥连弩,每个出牌阶段只能使用一次“杀”来攻击。
    任何牌被使用后被弃置(武器是装备上)。
    被弃置的牌以后都不能再用,即与游戏无关。
    各种牌介绍
    每张手牌用一个字母表示,字母代表牌的种类。
    基本牌
    『桃(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++) 语言来帮他预测最后的结果

    INPUT

    第一行包含两个正整数n(2 <= n <= 10) 和m( m <= 2000),分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。 接下来n行,每行5个字符串,依次表示对第i只猪的角色和初始4张手牌描述。编号为1的肯定是主猪。 再接下来一行,一共m个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。 所有的相邻的两个字符串都严格用1个空格隔开,行尾没有多余空格。

    OUTPUT

    输出数据第一行包含一个字符串代表游戏结果。如果是主猪胜利,那么输出“MP”,否则输出“FP”。数据保证游戏总会结束。 接下来n行,第i行是对第i只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用一个空格隔开,行末尾没有多余空格。如果这只猪已阵亡,那么只要输出“DEAD”即可。注意如果要输出手牌而没有手牌的话,那么只需输出一个空行。

    SAMPLE

    INPUT

    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

    OUTPUT

    FP
    DEAD
    DEAD
    J J J J J D

    解题报告

    打了我多长时间,466行,9.32 KB,太可怕了太可怕了

    不要相信鬼题面,牌堆没了一直抽最后一张就好了QAQ

    看注释看注释,大模拟真的没啥可写的QAQ

    虽然还是很恶心QAQ

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 using namespace std;
      5 char card[5005],paidui[5005],op[5];//card 所有牌 paidui 牌堆
      6 int pre[5005],nxt[5005],cnt;//牌的链表
      7 int top,bot,m,n;//top 牌堆顶 bot 读入时往牌堆里压
      8 int sumf;//sumf 反贼数量
      9 int zhugong;//主公
     10 bool gameover;
     11 inline char get_card(){
     12     if(top!=m)
     13         ++top;
     14     return paidui[top];//听说没牌了要一直摸最后一张
     15 }
     16 inline void kill(int,int);
     17 inline void fight(int,int);
     18 inline void nanman(int);
     19 inline void wanjian(int);
     20 inline void hurt(int,int);
     21 inline void godie(int,int);
     22 inline bool wuxiekeji(int,bool);
     23 struct piggy{
     24     int id,appear,blood,num;//id 身份 1主公 2忠臣 3反贼 appear 跳的情况 0 没跳 1 类反 2跳忠 3跳反 num 几号
     25     int nump,numk,numd,numf,numn,numw,numj;//各牌的数量 p 桃 k 杀 d 闪 f 决斗 n 南蛮 w 万箭 j 无懈
     26     bool zhuge,dead;//诸葛 死没死
     27     int prepig,nxtpig,head,last,now,tmp;//链表 牌的链表
     28     int attack;//首要攻击目标
     29     piggy():appear(0),blood(4),nump(0),numk(0),numd(0),numf(0),numn(0),numw(0),numj(0),head(0),last(0),now(0),attack(0){}
     30     inline void mopai(){//摸一张牌
     31         card[++cnt]=get_card();
     32         pre[cnt]=last;
     33         if(!head)head=last=cnt;
     34         else nxt[last]=cnt,last=cnt;//更新链表
     35         if(card[cnt]=='P')++nump;
     36         if(card[cnt]=='K')++numk;
     37         if(card[cnt]=='D')++numd;
     38         if(card[cnt]=='F')++numf;
     39         if(card[cnt]=='N')++numn;
     40         if(card[cnt]=='W')++numw;
     41         if(card[cnt]=='J')++numj;
     42     }
     43     inline void award(){//杀一个的奖励
     44         mopai(),mopai(),mopai();
     45     }
     46     inline void punish(){//杀错的惩罚
     47         head=last=now=nump=numk=numd=numf=numn=numw=numj=0;
     48         zhuge=false;
     49     }
     50     inline void mopaistage(){//摸牌阶段
     51         mopai(),mopai();
     52     }
     53     inline void use(int x){//打出一张牌
     54         if(card[x]=='P')--nump;
     55         if(card[x]=='K')--numk;
     56         if(card[x]=='D')--numd;
     57         if(card[x]=='F')--numf;
     58         if(card[x]=='N')--numn;
     59         if(card[x]=='W')--numw;
     60         if(card[x]=='J')--numj;
     61         if(x==head&&x==last)head=last=0;
     62         else
     63             if(x==head)
     64                 head=nxt[x],pre[head]=0;
     65             else
     66                 if(x==last)
     67                     last=pre[x],nxt[last]=0;
     68                 else
     69                     pre[nxt[x]]=pre[x],nxt[pre[x]]=nxt[x];//更新链表
     70     }
     71     inline char get_nxt(){//找下一张牌
     72         if(!now)return 0;
     73         tmp=now;
     74         now=nxt[now];
     75         return card[tmp];
     76     }
     77     inline int findp(){//找桃
     78         now=head;
     79         char tp;
     80         while(tp=get_nxt())
     81             if(tp=='P')
     82                 return tmp;
     83     }
     84     inline int findk(){//找杀
     85         now=head;
     86         char tp;
     87         while(tp=get_nxt())
     88             if(tp=='K')
     89                 return tmp;
     90     }
     91     inline int findd(){//找闪
     92         now=head;
     93         char tp;
     94         while(tp=get_nxt())
     95             if(tp=='D')
     96                 return tmp;
     97     }
     98     inline int findf(){//找决斗
     99         now=head;
    100         char tp;
    101         while(tp=get_nxt())
    102             if(tp=='F')
    103                 return tmp;
    104     }
    105     inline int findn(){//找南蛮
    106         now=head;
    107         char tp;
    108         while(tp=get_nxt())
    109             if(tp=='N')
    110                 return tmp;
    111     }
    112     inline int findw(){//找万箭
    113         now=head;
    114         char tp;
    115         while(tp=get_nxt())
    116             if(tp=='W')
    117                 return tmp;
    118     }
    119     inline int findj(){//找无懈
    120         now=head;
    121         char tp;
    122         while(tp=get_nxt())
    123             if(tp=='J')
    124                 return tmp;
    125     }
    126     inline bool qiup(){//尝试出桃,返回是否出成桃
    127         if(nump){
    128             use(findp());
    129             return true;
    130         }
    131         return false;
    132     }
    133     inline bool qiuk(){//尝试出杀
    134         if(numk){
    135             use(findk());
    136             return true;
    137         }
    138         return false;
    139     }
    140     inline bool qiud(){//尝试出闪
    141         if(numd){
    142             use(findd());
    143             return true;
    144         }
    145         return false;
    146     }
    147     inline bool qiuf(){//尝试出决斗
    148         if(numf){
    149             use(findf());
    150             return true;
    151         }
    152         return false;
    153     }
    154     inline bool qiun(){//尝试出南蛮
    155         if(numn){
    156             use(findn());
    157             return true;
    158         }
    159         return false;
    160     }
    161     inline bool qiuw(){//尝试出万箭
    162         if(numw){
    163             use(findw());
    164             return true;
    165         }
    166         return false;
    167     }
    168     inline bool qiuj(){//尝试出无懈
    169         if(numj){
    170             use(findj());
    171             return true;
    172         }
    173         return false;
    174     }
    175     inline void round(){//回合
    176         mopaistage();
    177 //      cout<<"mopai is over "<<cnt<<endl;
    178         now=head;
    179         char tp;
    180         bool usedsha(false);
    181         while((tp=get_nxt())&&!gameover){
    182 //          cout<<"now the card is "<<tp<<endl;
    183             if(tp=='D'||tp=='J')continue;
    184             if(tp=='P'){
    185                 if(blood<4)
    186                     ++blood,use(tmp);
    187                 continue;
    188             }
    189             if(tp=='K'){
    190                 if(attack==nxtpig){
    191                     if(!usedsha||zhuge){
    192                         use(tmp);
    193                         kill(num,attack);
    194                         usedsha=true;
    195                         now=head;
    196                         if(gameover)return;
    197                     }
    198                 }
    199                 continue;
    200             }
    201             if(tp=='F'){
    202                 if(!attack)continue;
    203                 use(tmp);
    204                 if(id==3)fight(num,1);
    205                 else fight(num,attack);
    206                 now=head;
    207                 if(gameover||dead)return;//决斗可以自杀
    208                 continue;
    209             }
    210             if(tp=='N'){
    211                 use(tmp);
    212                 nanman(num);
    213                 now=head;
    214                 if(gameover)return;
    215                 continue;
    216             }
    217             if(tp=='W'){
    218                 use(tmp);
    219                 wanjian(num);
    220                 now=head;
    221                 if(gameover)return;
    222                 continue;
    223             }
    224             if(tp=='Z'){
    225                 use(tmp);
    226                 zhuge=true;
    227                 now=head;//从头开始出,因为诸葛可以让前面的杀出来,前面的也是这个作用
    228                 continue;
    229             }
    230         }
    231     }
    232     inline void print(){
    233         if(dead)puts("DEAD");
    234         else{
    235             while(head){
    236                 printf("%c",card[head]);
    237                 if(head!=last)putchar(' ');
    238                 head=nxt[head];
    239             }
    240             puts("");
    241         }
    242     }
    243 }a[15];
    244 inline void cal_attack(int x){//计算攻击目标
    245     int y(a[x].nxtpig);
    246     if(a[x].id==1){
    247         while(y!=x){
    248             if(a[y].appear==1||a[y].appear==3){
    249                 a[x].attack=y;
    250                 return;
    251             }
    252             y=a[y].nxtpig;
    253         }
    254     }
    255     if(a[x].id==2){
    256         while(y!=x){
    257             if(a[y].appear==3){
    258                 a[x].attack=y;
    259                 return;
    260             }
    261             y=a[y].nxtpig;
    262         }
    263     }
    264     if(a[x].id==3){
    265         while(y!=x){
    266             if(a[y].appear==2||a[y].id==1){
    267                 a[x].attack=y;
    268                 return;
    269             }
    270             y=a[y].nxtpig;
    271         }
    272     }
    273     a[x].attack=0;
    274 }
    275 inline void allcal(){//所有猪计算一遍
    276     int x(a[zhugong].nxtpig);
    277     cal_attack(zhugong);
    278     while(x!=zhugong){
    279         cal_attack(x);
    280         x=a[x].nxtpig;
    281     }
    282 }
    283 inline void hurt(int x,int y){//x对y造成伤害
    284     --a[y].blood;
    285 //  cout<<"now "<<x<<" hurt "<<y<<endl;
    286     if(!a[y].blood){
    287         if(a[y].qiup())++a[y].blood;
    288         else godie(x,y);
    289     }
    290 }
    291 inline void godie(int x,int y){//x杀死了y
    292     a[y].dead=true;
    293     if(a[y].id==1){
    294         gameover=true;
    295         return;
    296     }
    297     if(a[y].id==3){
    298         --sumf;
    299         if(!sumf){
    300             gameover=true;
    301             return;
    302         }
    303         a[x].award();
    304     }
    305     if(a[y].id==2&&a[x].id==1)
    306         a[x].punish();
    307     a[a[y].prepig].nxtpig=a[y].nxtpig;
    308     a[a[y].nxtpig].prepig=a[y].prepig;
    309     allcal();
    310 }
    311 inline void kill(int x,int y){//x对y使用了一张杀
    312     if(a[x].id!=1&&a[x].appear<2){
    313         if(a[y].id==3)a[x].appear=2;
    314         else a[x].appear=3;
    315         allcal();
    316     }
    317     if(a[y].qiud())return;
    318     hurt(x,y);
    319 }
    320 inline void fight(int x,int y){//x对y决斗
    321     if(a[x].id!=1&&a[x].appear<2){
    322         if(a[y].id==3)a[x].appear=2;
    323         else a[x].appear=3;
    324         allcal();
    325     }
    326     if(a[y].id==1||a[y].appear==2)
    327         if(wuxiekeji(x,0))
    328             return;
    329     if(a[y].appear==3)
    330         if(wuxiekeji(x,1))
    331             return;
    332     if(a[x].id==1&&a[y].id==2){
    333         hurt(x,y);
    334         return;
    335     }
    336     while(1){
    337         if(!a[y].qiuk()){
    338             hurt(x,y);
    339             return;
    340         }
    341         if(!a[x].qiuk()){
    342             hurt(y,x);
    343             return;
    344         }
    345     }
    346 }
    347 inline void nanman(int x){//x使用了南蛮
    348     int y(a[x].nxtpig);
    349 //  cout<<"now "<<x<<" is nanmaning"<<endl;
    350     while(y!=x){
    351         if(a[y].id==1||a[y].appear==2)
    352             if(wuxiekeji(x,0)){
    353 //              cout<<"wuxiekeji "<<y<<endl;
    354                 y=a[y].nxtpig;
    355                 continue;
    356             }
    357         if(a[y].appear==3)
    358             if(wuxiekeji(x,1)){
    359 //              cout<<"wuxiekeji "<<y<<endl;
    360                 y=a[y].nxtpig;
    361                 continue;
    362             }
    363         if(!a[y].qiuk()){
    364             hurt(x,y);
    365             if(gameover)return;
    366             if(y==1&&a[x].appear==0){
    367                 a[x].appear=1;
    368                 allcal();
    369             }
    370         }
    371         y=a[y].nxtpig;
    372     }
    373 }
    374 inline void wanjian(int x){//x使用了万箭
    375     int y(a[x].nxtpig);
    376     while(y!=x){
    377         if(a[y].id==1||a[y].appear==2)
    378             if(wuxiekeji(x,0)){
    379                 y=a[y].nxtpig;
    380                 continue;
    381             }
    382         if(a[y].appear==3)
    383             if(wuxiekeji(x,1)){
    384                 y=a[y].nxtpig;
    385                 continue;
    386             }
    387         if(!a[y].qiud()){
    388             hurt(x,y);
    389             if(gameover)return;
    390             if(y==1&&a[x].appear==0){
    391                 a[x].appear=1;
    392                 allcal();
    393             }
    394         }
    395         y=a[y].nxtpig;
    396     }
    397 }
    398 inline bool wuxiekeji(int pos,bool fan){
    399     bool st(fan);
    400     int last(pos),x(pos);
    401     if(fan==(a[x].id==3)){
    402         if(a[x].qiuj()){
    403             last=x;
    404             fan=!fan;
    405             if(a[x].appear<=2){
    406                 a[x].appear=3-fan;
    407                 allcal();
    408             }
    409         }
    410     }
    411     x=a[x].nxtpig;
    412     while(x!=last){
    413         if(fan==(a[x].id==3)){
    414             if(a[x].qiuj()){
    415                 last=x;
    416                 fan=!fan;
    417                 if(a[x].appear<=2){
    418                     a[x].appear=3-fan;
    419                     allcal();
    420                 }
    421             }
    422         }
    423         x=a[x].nxtpig;
    424     }
    425     return st!=fan;
    426 }
    427 int main(){
    428     scanf("%d%d",&n,&m);
    429     for(int i=1;i<=n;++i)
    430         a[i].prepig=i-1,a[i].nxtpig=i+1;
    431     a[1].prepig=n,a[n].nxtpig=1;
    432     for(int i=1;i<=n;++i){
    433         scanf("%s",op);
    434         if(op[0]=='M')a[i].id=1,zhugong=i;
    435         if(op[0]=='Z')a[i].id=2;
    436         if(op[0]=='F')a[i].id=3,++sumf;
    437         for(int j=1;j<=4;++j){
    438             scanf("%s",op);
    439             paidui[++bot]=op[0];
    440         }
    441     }
    442     for(int i=1;i<=m;++i){
    443         scanf("%s",op);
    444         paidui[++bot]=op[0];
    445     }
    446     m+=(n<<2);
    447     for(int i=1;i<=n;++i){
    448         a[i].mopaistage();
    449         a[i].mopaistage();
    450         a[i].num=i;
    451     }
    452     allcal();
    453     int now(1);
    454     while(!gameover){
    455 //      cout<<"now start "<<now<<" turn"<<endl;
    456         a[now].round();
    457         now=a[now].nxtpig;
    458 //      cout<<"check the blood"<<endl;
    459 //      for(int i=1;i<=n;++i)
    460 //          cout<<i<<" is "<<((a[i].dead)?"dead":"live")<<" blood "<<a[i].blood<<endl;
    461     }
    462     if(a[zhugong].dead)puts("FP");
    463     else puts("MP");
    464     for(int i=1;i<=n;++i)
    465         a[i].print();
    466 }
    View Code
  • 相关阅读:
    mysql时间日期的加、减
    IDEA 下的svn检出maven代码
    IDEA中如何显示和关闭工具栏、目录栏
    Idea集成使用SVN教程
    Python PEP8 代码规范常见问题及解决方法
    Word文档中手写签名操作说明
    19.名称空间和作用域
    18.函数的参数
    17.文件处理
    16.字符编码
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7647505.html
Copyright © 2020-2023  润新知