真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[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\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 }
View Code

 

posted @ 2017-10-10 19:53  Hzoi_Mafia  阅读(893)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神