[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 10MP D D F FZP N N N DFP J J J JF F D D J J F F K DOUTPUT
FPDEADDEADJ 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\0":"live\0")<<" 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 }