猪国杀
前言
这道题是一道大模拟,个人认为还是挺锻炼码力的,所以本蒟蒻花一天的时间,爆肝一周的时间终于写完了。。。
题意
游戏目的
主猪 /
MP
\texttt{MP}
MP:自己存活的情况下消灭所有的反猪。
忠猪 /
ZP
\texttt{ZP}
ZP:不惜一切保护主猪,胜利条件与主猪相同。
反猪 /
FP
\texttt{FP}
FP:杀死主猪。
游戏过程
游戏开始时,每个玩家手里都会有 4 4 4 张牌,且体力上限和初始体力都是 4 4 4 。
开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1 , 2 , 3 … n , 1 … 1 , 2, 3 \ldots n , 1 \ldots 1,2,3…n,1… 的顺序)依次行动。
每个玩家自己的回合可以分为 2 2 2 个阶段:
- 摸牌阶段:从牌堆顶部摸 2 2 2 张牌,依次放到手牌的最右边;
- 出牌阶段:你可以使用任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。当然,要满足如下规则:
- 如果没有猪哥连弩,每个出牌阶段只能使用 1 1 1 次「杀」来攻击;
- 任何牌被使用后被弃置(武器是装备上);被弃置的牌以后都不能再用,即与游戏无关。
牌的种类
基本牌
-
『桃 / P \texttt{P} P』在自己的回合内,如果自己的体力值不等于体力上限,那么使用 1 1 1 个桃可以为自己补充 1 1 1 点体力,否则不能使用桃;桃只能对自己使用;在自己的回合外,如果自己的血变为 0 0 0 或者更低,那么也可以使用。
-
『杀 / K \texttt{K} K』在自己的回合内,对攻击范围内除自己以外的 1 1 1 名角色使用。如果没有被『闪』抵消,则造成 1 1 1 点伤害。无论有无武器,杀的攻击范围都是 1 1 1。
-
『闪 / D \texttt{D} D』当你受到杀的攻击时,可以弃置 1 1 1 张闪来抵消杀的效果。
锦囊牌
-
『决斗 / F \texttt{F} F』出牌阶段,对除自己以外任意 1 1 1 名角色使用,由目标角色先开始,自己和目标角色轮流弃置 1 1 1 张杀,首先没有杀可弃的一方受到 1 1 1 点伤害,另一方视为此伤害的来源。
-
『南猪入侵 / N \texttt{N} N』出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置 1 1 1 张杀,否则受到 1 1 1 点伤害。
-
『万箭齐发 / W \texttt{W} W』和南猪入侵类似,不过要弃置的不是杀而是闪。
-
『无懈可击 / J \texttt{J} J』在目标锦囊生效前抵消其效果。每次有 1 1 1 张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会;效果:用于决斗时,决斗无效并弃置;用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对 1 1 1 个角色产生效果);用于无懈可击时,成为目标的无懈可击被无效。
装备牌
- 『猪哥连弩 / Z \texttt{Z} Z』武器,攻击范围 1 1 1 ,出牌阶段你可以使用任意张杀; 同一时刻最多只能装 1 1 1 把武器;如果先前已经有了 1 1 1 把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。
特殊事件及概念解释
-
伤害来源:杀、南猪入侵、万箭齐发的伤害来源均是使用该牌的猪,决斗的伤害来源如上;
-
距离:两只猪的距离定义为沿着逆时针方向间隔的猪数 + 1 +1 +1 。即初始时 1 1 1 和 2 2 2 的距离为 1 1 1 ,但是 2 2 2 和 1 1 1 的距离就是 n − 1 n-1 n−1 。注意一个角色的死亡会导致一些猪距离的改变;
-
玩家死亡:如果该玩家的体力降到 0 0 0 或者更低,并且自己手中没有足够的桃使得自己的体力值回到 1 1 1 ,那么就死亡了,死亡后所有的牌(装备区,手牌区)被弃置;
-
奖励与惩罚:反猪死亡时,最后一个伤害来源处(即使是反猪)立即摸 3 3 3 张牌。忠猪死亡时,如果最后一个伤害来源是主猪,那么主猪所有装备牌、手牌被弃置。
注意:一旦达成胜利条件,游戏立刻结束,因此即使会摸 3 3 3 张牌或者还有牌可以用也不用执行了。
现在,我们已经知道每只猪的角色、手牌,还有牌堆初始情况,并且假设每个角色会按照如下的行为准则进行游戏,你需要做的就是告诉小猪 iPig 最后的结果。
几种行为
- 献殷勤:使用无懈可击挡下南猪入侵、万箭齐发、决斗;使用无懈可击抵消表敌意;
- 表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤;
- 跳忠:即通过行动表示自己是忠猪。跳忠行动就是对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意;
- 跳反:即通过行动表示自己是反猪。跳反行动就是对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤。
注意:忠猪不会跳反,反猪也不会跳忠;不管是忠猪还是反猪,能够跳必然跳。
行动准则
共性
- 每个角色如果手里有桃且生命值未满,那么必然吃掉;
- 有南猪入侵、万箭齐发、必然使用;有装备必然装上;
- 受到杀时,有闪必然弃置;
- 响应南猪入侵或者万箭齐发时候,有杀 / 闪必然弃置;
- 不会对未表明身份的猪献殷勤(包括自己)。
特性
- 主猪:
- 主猪会认为「没有跳身份,且用南猪入侵 / 万箭齐发对自己造成伤害的猪」是类反猪(没伤害到不算,注意类反猪并没有表明身份),如果之后跳了,那么主猪会重新认识这只猪;
- 对于每种表敌意的方式,对逆时针方向能够执行到的第一只类反猪或者已跳反猪表;如果没有,那么就不表敌意;
- 决斗时会不遗余力弃置杀;
- 如果能对已经跳忠的猪或自己献殷勤,那么一定献;如果能够对已经跳反的猪表敌意,那么一定表。
- 忠猪:
- 对于每种表敌意的方式,对「逆时针方向能够执行到的第一只已经跳反的猪」表,如果没有,那么就不表敌意;
- 决斗时,如果对方是主猪,那么不会弃置杀,否则,会不遗余力弃置杀;
- 如果有机会对主猪或者已经跳忠的猪献殷勤,那么一定献。
- 反猪:
- 对于每种表敌意的方式,如果有机会则对主猪表,否则,对「逆时针方向能够执行到的第一只已经跳忠的猪」表,如果没有,那么就不表敌意;
- 决斗时会不遗余力弃置杀;
- 如果有机会对已经跳反的猪献殷勤,那么一定献。
做法
本蒟蒻刚刚看到题一脸懵逼,主要是卡在了无懈可击的生效前的意思,举个例子, A A A 使出了『南猪入侵』,逆时针结算到 B B B 时,若 A A A 与 B B B 不是相同的组别,与 A A A 一队的猪就会努力使锦囊生效,与 B B B 为一个组别的猪就会想法设法的使锦囊失效。
其中这题的部分分为:
- 10 10 10 分:没有锦囊牌。
- 30 30 30 分:没有无懈可击。
- 100 100 100 分: n ≤ 10 n \le10 n≤10, m ≤ 1000 m \le 1000 m≤1000。
10 10 10 分,没有锦囊牌
辅助数组
一下只列举出比较重要的几个函数。
- string pig[i]:表示第 i i i 只猪的身份。
- char c[i][j]:表示第 i i i 只猪的第 j j j 张卡牌是多少。
- int bld[i]:blood 的缩写,意思为第 i i i 只猪的血量。
- int tot[i]:表示第 i i i 只猪的总卡牌数量(被用掉的也算),主要是为了实现一些卡牌删除与加入。
- int lpig[i]:表示第 i i i 只猪的左边一只猪是几号,其中 1 1 1 的左边是 n n n。
- int rpig[i]:表示第 i i i 只猪的右边一只猪是几号,其中 n n n 的右边是 1 1 1。
其中 lpig[i]
与 rpig[i]
为类似双链表的东西。
- bool tfpig[i]:表示第 i i i 只猪是否为类反猪。
- bool iden[i]:表示第 i i i 只猪是否跳身份。
- bool flag[i][j]:表示第 i i i 只猪的第 j j j 张卡牌是否被用。
辅助函数
- count(x, t):表示第 i i i 只猪的卡牌中有几张为 t t t 的卡牌。
int count(int x, char t) {
int res = 0;
for (int i = 1; i <= tot[x]; i++)
if (!flag[x][i] && c[x][i] == t)
res++;
return res;
}
- del(x, k, t):从c[x]中删除k个字符t。
void del(int x, int k, char t) {
if (k <= 0) return;
int cnt = 0;
for (int i = 1; i <= tot[x] && cnt < k; i++)
if (!flag[x][i] && c[x][i] == t)
flag[x][i] = true, cnt++;
}
- peach(i):在自己的回合回血。
void peach(int x) {
if (bld[x] < 4) { bld[x]++; del(x, 1, 'P'); }
}
- bld_back(i):在别人的回合内回血。
bool bld_back(int x) {
if (bld[x] > 0) return false;
bool ok = false; // 是否阵亡
int P = count(x, 'P');
if (abs(bld[x]) + 1 <= P) { del(x, abs(bld[x]) + 1, 'P'); bld[x] = 1; }
else { ok = true; thrw(x); }
return ok;
}
要注意 peach 和 bld_back 这两个函数的区别:peach 是最多只能回到
4
4
4,而 bld_back 是当前这头猪在血量小于等于
0
0
0 时,用桃将其血量回到
1
1
1。
5. Dead(x, y):表示
x
x
x 将
y
y
y 弄(可能是南猪入侵、万箭齐发、决斗或者杀)死后的处理:
- p i g [ y ] pig[y] pig[y] 为主猪,直接输出
- p i g [ y ] pig[y] pig[y] 为反猪,若反猪数量为 0 0 0,直接输出,否则 x x x 加 3 3 3 张牌。
- p i g [ x ] pig[x] pig[x] 为主猪,则将主猪的所有牌弃置。
void Dead(int x, int y) {
dead[y] = true;
rpig[lpig[y]] = rpig[y];
lpig[rpig[y]] = lpig[y];
if (x == y) return;
if (pig[y] == "MP") { Print(); exit(0); }
else if (pig[y] == "FP") {
if (--fpig == 0) { Print(); exit(0); }
In(x, 3);
} else if (pig[x] == "MP") thrw(x);
}
其中 In(i, 3)
表示
i
i
i 加入两张牌,thrw(i):表示将
i
i
i 的所有牌弃置(包括装备牌)。
将以上的代码组成一个程序即可,这里就不在做详细的解释了,但是为了代码简洁清晰,强烈推荐使用switch case
。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, bld[15], fpig, idx = 0, tot[15], rpig[15], lpig[15];
char c[15][10010], card[10010];
bool tfpig[15], arm[15], flag[15][10010], iden[15], dead[15];
string pig[15];
// c[i][j]:表示第i只猪的第j张牌为c[i][j]。
// tot[i]:表示第i只猪有多少张牌。
// pig[i]:表示第i只猪的角色。
// bld[i]:表示第i只猪的血量值。
// fpig:表示活的反猪的数量。
// tfpig[i]:表示第i只猪是否为类反猪。
// arm[i]:表示第i只猪是否有装备。
// flag[i][j]:表示第i只猪的第j张牌是否被用过。
// iden[i]:表示第i只猪是否已经跳身份。
void Read() {
iden[1] = true;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> pig[i];
bld[i] = 4;
for (int j = 1; j <= 4; j++) cin >> c[i][++tot[i]];
if (pig[i] == "FP") fpig++;
if (i == n) rpig[i] = 1;
else rpig[i] = i + 1;
if (i == 1) lpig[i] = n;
else lpig[i] = i - 1;
}
for (int i = 1; i <= m; i++) cin >> card[i];
} // 读入
void Print() {
if (fpig == 0) cout << "MP" << endl;
else cout << "FP" << endl;
for (int i = 1; i <= n; i++)
if (dead[i]) cout << "DEAD" << endl;
else {
int cnt = 0, res = 0;
for (int j = 1; j <= tot[i]; j++) if (!flag[i][j]) cnt++;
for (int j = 1; j <= tot[i]; j++)
if (!flag[i][j] && res != cnt - 1) cout << c[i][j] << " ";
else if (!flag[i][j] && res == cnt - 1) cout << c[i][j];
if (!cnt) cout << " ";
cout << endl;
}
}
void thrw(int x) {
for (int i = 1; i <= tot[x]; i++) flag[x][i] = true;
arm[x] = false;
} // 将第i只猪的手牌和装备弃置
void In(int x, int k) {
for (int i = idx + 1; i <= idx + k; i++) c[x][++tot[x]] = card[min(m, i)];
idx += k;
}// 摸k张牌
int count(int x, char t) {
int res = 0;
for (int i = 1; i <= tot[x]; i++)
if (!flag[x][i] && c[x][i] == t)
res++;
return res;
}// 统计第i只猪有几张t这张牌
void del(int x, int k, char t) {
if (k <= 0) return;
int cnt = 0;
for (int i = 1; i <= tot[x] && cnt < k; i++)
if (!flag[x][i] && c[x][i] == t)
flag[x][i] = true, cnt++;
}// 从c[x]中删除k个字符t。
void peach(int x) {
if (bld[x] < 4) { bld[x]++; del(x, 1, 'P'); }
} // 在自己的回合回血
bool bld_back(int x) {
if (bld[x] > 0) return false;
bool ok = false; // 是否阵亡
int P = count(x, 'P');
if (abs(bld[x]) + 1 <= P) { del(x, abs(bld[x]) + 1, 'P'); bld[x] = 1; }
else { ok = true; thrw(x); }
return ok;
} // 在别人的回合回血
void Dead(int x, int y) {
dead[y] = true;
rpig[lpig[y]] = rpig[y];
lpig[rpig[y]] = lpig[y];
if (x == y) return;
if (pig[y] == "MP") { Print(); exit(0); }
else if (pig[y] == "FP") {
if (--fpig == 0) { Print(); exit(0); }
In(x, 3);
} else if (pig[x] == "MP") thrw(x);
} // x杀死了y。
void kill(int i, int pos) {
iden[i] = true;
int D = count(pos, 'D'); // 统计闪的数量
int K = 1;
if (D >= 1) { K = 0; del(pos, 1, 'D'); }
del(i, 1, 'K');
bld[pos] -= K;
if (bld[pos] <= 0) { bool f = bld_back(pos); if (f) Dead(i, pos); } // 对pos这头猪回血
} // i对pos使用杀
void Arm(int x) { arm[x] = true; del(x, 1, 'Z'); }
int find(string op, int i) {
int pos = -1;
if (i == n && op == "FP") pos = 1; // 特判
for (int j = i + 1; j <= n && pos == -1; j++)
if (op == "MP" && (pig[j] == "FP" && iden[j] || tfpig[j]) && bld[j] > 0) { pos = j; break; }
else if (op == "ZP" && pig[j] == "FP" && iden[j] && bld[j] > 0) { pos = j; break; }
else if (op == "FP" && pig[j] == "ZP" && iden[j] && bld[j] > 0) { pos = j; break; }
for (int j = 1; j < i && pos == -1; j++)
if (op == "MP" && (pig[j] == "FP" && iden[j] || tfpig[j]) && bld[j] > 0) { pos = j; break; }
else if (op == "ZP" && pig[j] == "FP" && iden[j] && bld[j] > 0) { pos = j; break; }
else if (op == "FP" && pig[j] == "ZP" && iden[j] && bld[j] > 0) { pos = j; break; }
return pos;
} // 找到对应种类的猪所要找到的杀的对象,没找到返回-1。
bool find_to_kill(string op, int x) {
bool can = false;
string nxt = pig[rpig[x]];
if (op == "MP" && (nxt == "FP" && iden[rpig[x]] || tfpig[rpig[x]])) can = true;
else if (op == "ZP" && nxt != "MP" && iden[rpig[x]] && pig[rpig[x]] == "FP") can = true;
else if (op == "FP" && nxt != "FP" && (rpig[x] == 1 || iden[rpig[x]] && pig[rpig[x]] == "ZP")) can = true;
return can;
}
void play(int x) { // 模拟
In(x, 2);
bool ok = false, use_K = false;
for (int i = 1; i <= tot[x]; i++) {
if (flag[x][i]) continue;
char now = c[x][i];
switch (now) {
case 'P': peach(x); break;
case 'K':
if (find_to_kill(pig[x], x) && (!arm[x] && !use_K || arm[x])) { kill(x, rpig[x]), use_K = true; }
break;
case 'Z': Arm(x); break;
}
if (dead[x]) break;
}
}
void work() {
int i = 0;
while (fpig && bld[1] > 0) {
i = i % n + 1;
if (dead[i]) continue;
else play(i);
}
}
int main() {
Read();
work();
Print();
return 0;
}
30 30 30 分,没有无懈可击
决斗
决斗说白了就是两个人同时弃置一张杀,被决斗者先出,谁先没有杀就扣一滴血。假设 x x x 向 y y y 发起了决斗,分别统计 x x x 的杀的数量以及 y y y 杀的数量,记作 x K xK xK 和 y K yK yK。
- 若 x K ≥ y K xK \ge yK xK≥yK:则 y y y 扣一滴血。
- 若 x K < y K xK < yK xK<yK:则 x x x 扣一滴血。
void fight(int x, int y) {
del(x, 1, 'F');
iden[x] = true;
if (pig[x] == "MP" && pig[y] == "ZP" && tfpig[y] && !iden[y]) {
if (--bld[y] <= 0) { int f = bld_back(y); if (f) Dead(x, y); }
return;
}
int xK = count(x, 'K');
int yK = count(y, 'K');
int man, toman;
if (xK >= yK) { toman = x, man = y, bld[y]--; del(x, yK, 'K'), del(y, yK, 'K'); }
else { man = x, toman = y, bld[x]--; del(y, xK + 1, 'K'), del(x, xK, 'K'); }
if (bld[man] <= 0) { int f = bld_back(man); if (f) Dead(toman, man); }
}
南猪入侵
从使用者的下一位开始,依次弃置一张杀,若没有就扣一滴血。按意思模拟即可,但是当结算到第 i i i 头猪要判断下是否死亡。假设枚举到了第 i i i 只猪:
- 有 K K K:啥事都不用干。
- 没有 K K K:扣一滴血,若 p i g [ i ] pig[i] pig[i] 为主猪,则使用者将成为类反猪(若已经跳身份的不算)。
// 处理
void Initnanzhu(int j, int x) {
if (bld[j] <= 0) return ;
int K = count(j, 'K');
if (K > 0) del(j, 1, 'K');
else {
bool f = true;
if (--bld[j] <= 0) {
int P = count(j, 'P');
if (P == 0) Dead(x, j);
else bld[j]++, del(j, 1, 'P'), f = false;
}
if (j == 1 && f) tfpig[x] = true;
}
}
// 枚举
void nanzhu(int x) {
del(x, 1, 'N');
for (int j = x + 1; j <= n; j++) Initnanzhu(j, x);
for (int j = 1; j < x; j++) Initnanzhu(j, x);
}
万箭齐发
同理南猪入侵,区别为将杀改成了闪。
// 处理
void Initwanjian(int j, int x) {
if (dead[j]) return;
int D = count(j, 'D');
if (D > 0) del(j, 1, 'D');
else {
bool f = true;
if (--bld[j] <= 0) {
int P = count(j, 'P');
if (P == 0) Dead(x, j);
else bld[j]++, del(j, 1, 'P'), f = false;
}
if (j == 1 && f) tfpig[x] = true;
}
}
// 枚举
void wanjian(int x) {
del(x, 1, 'W');
for (int j = x + 1; j <= n; j++) Initwanjian(j, x);
for (int j = 1; j < x; j++) Initwanjian(j, x);
}
代码
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, bld[15], fpig, idx = 0, tot[15], rpig[15], lpig[15];
char c[15][10010], card[10010];
bool tfpig[15], arm[15], flag[15][10010], iden[15], dead[15];
string pig[15];
// c[i][j]:表示第i只猪的第j张牌为c[i][j]。
// tot[i]:表示第i只猪有多少张牌。
// pig[i]:表示第i只猪的角色。
// bld[i]:表示第i只猪的血量值。
// fpig:表示活的反猪的数量。
// tfpig[i]:表示第i只猪是否为类反猪。
// arm[i]:表示第i只猪是否有装备。
// flag[i][j]:表示第i只猪的第j张牌是否被用过。
// iden[i]:表示第i只猪是否已经跳身份。
void Read() {
iden[1] = true;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> pig[i];
bld[i] = 4;
for (int j = 1; j <= 4; j++) cin >> c[i][++tot[i]];
if (pig[i] == "FP") fpig++;
if (i == n) rpig[i] = 1;
else rpig[i] = i + 1;
if (i == 1) lpig[i] = n;
else lpig[i] = i - 1;
}
for (int i = 1; i <= m; i++) cin >> card[i];
} // 读入
void Print() {
if (fpig == 0) cout << "MP" << endl;
else cout << "FP" << endl;
for (int i = 1; i <= n; i++)
if (dead[i]) cout << "DEAD" << endl;
else {
int cnt = 0, res = 0;
for (int j = 1; j <= tot[i]; j++) if (!flag[i][j]) cnt++;
for (int j = 1; j <= tot[i]; j++)
if (!flag[i][j] && res != cnt - 1) cout << c[i][j] << " ";
else if (!flag[i][j] && res == cnt - 1) cout << c[i][j];
if (!cnt) cout << " ";
cout << endl;
}
}
void thrw(int x) {
for (int i = 1; i <= tot[x]; i++) flag[x][i] = true;
arm[x] = false;
} // 将第i只猪的手牌和装备弃置
void In(int x, int k) {
for (int i = idx + 1; i <= idx + k; i++) c[x][++tot[x]] = card[min(m, i)];
idx += k;
}// 摸k张牌
int count(int x, char t) {
int res = 0;
for (int i = 1; i <= tot[x]; i++)
if (!flag[x][i] && c[x][i] == t)
res++;
return res;
}// 统计第i只猪有几张t这张牌
void del(int x, int k, char t) {
if (k <= 0) return;
int cnt = 0;
for (int i = 1; i <= tot[x] && cnt < k; i++)
if (!flag[x][i] && c[x][i] == t)
flag[x][i] = true, cnt++;
}// 从c[x]中删除k个字符t。
void peach(int x) {
if (bld[x] < 4) { bld[x]++; del(x, 1, 'P'); }
} // 在自己的回合回血
bool bld_back(int x) {
if (bld[x] > 0) return false;
bool ok = false; // 是否阵亡
int P = count(x, 'P');
if (abs(bld[x]) + 1 <= P) { del(x, abs(bld[x]) + 1, 'P'); bld[x] = 1; }
else { ok = true; thrw(x); }
return ok;
} // 在别人的回合回血
void Dead(int x, int y) {
dead[y] = true;
rpig[lpig[y]] = rpig[y];
lpig[rpig[y]] = lpig[y];
if (x == y) return;
if (pig[y] == "MP") { Print(); exit(0); }
else if (pig[y] == "FP") {
if (--fpig == 0) { Print(); exit(0); }
In(x, 3);
} else if (pig[x] == "MP") thrw(x);
} // x杀死了y。
void kill(int i, int pos) {
iden[i] = true;
int D = count(pos, 'D'); // 统计闪的数量
int K = 1;
if (D >= 1) { K = 0; del(pos, 1, 'D'); }
del(i, 1, 'K');
bld[pos] -= K;
if (bld[pos] <= 0) { bool f = bld_back(pos); if (f) Dead(i, pos); } // 对pos这头猪回血
} // i对pos使用杀
void fight(int x, int y) {
del(x, 1, 'F');
iden[x] = true;
if (pig[x] == "MP" && pig[y] == "ZP" && tfpig[y] && !iden[y]) {
if (--bld[y] <= 0) { int f = bld_back(y); if (f) Dead(x, y); }
return;
}
int xK = count(x, 'K');
int yK = count(y, 'K');
int man, toman;
if (xK >= yK) { toman = x, man = y, bld[y]--; del(x, yK, 'K'), del(y, yK, 'K'); }
else { man = x, toman = y, bld[x]--; del(y, xK + 1, 'K'), del(x, xK, 'K'); }
if (bld[man] <= 0) { int f = bld_back(man); if (f) Dead(toman, man); }
}// x向y发起决斗
void Initnanzhu(int j, int x) {
if (bld[j] <= 0) return ;
int K = count(j, 'K');
if (K > 0) del(j, 1, 'K');
else {
bool f = true;
if (--bld[j] <= 0) {
int P = count(j, 'P');
if (P == 0) Dead(x, j);
else bld[j]++, del(j, 1, 'P'), f = false;
}
if (j == 1 && f) tfpig[x] = true;
}
}
void Initwanjian(int j, int x) {
if (dead[j]) return;
int D = count(j, 'D');
if (D > 0) del(j, 1, 'D');
else {
bool f = true;
if (--bld[j] <= 0) {
int P = count(j, 'P');
if (P == 0) Dead(x, j);
else bld[j]++, del(j, 1, 'P'), f = false;
}
if (j == 1 && f) tfpig[x] = true;
}
}
void nanzhu(int x) {
del(x, 1, 'N');
for (int j = x + 1; j <= n; j++) Initnanzhu(j, x);
for (int j = 1; j < x; j++) Initnanzhu(j, x);
} // x 发起的南猪入侵
void wanjian(int x) {
del(x, 1, 'W');
for (int j = x + 1; j <= n; j++) Initwanjian(j, x);
for (int j = 1; j < x; j++) Initwanjian(j, x);
} // x 发起的万箭齐发
void Arm(int x) { arm[x] = true; del(x, 1, 'Z'); }
int find(string op, int i) {
int pos = -1;
if (i == n && op == "FP") pos = 1; // 特判
for (int j = i + 1; j <= n && pos == -1; j++)
if (op == "MP" && (pig[j] == "FP" && iden[j] || tfpig[j]) && bld[j] > 0) { pos = j; break; }
else if (op == "ZP" && pig[j] == "FP" && iden[j] && bld[j] > 0) { pos = j; break; }
else if (op == "FP" && pig[j] == "ZP" && iden[j] && bld[j] > 0) { pos = j; break; }
for (int j = 1; j < i && pos == -1; j++)
if (op == "MP" && (pig[j] == "FP" && iden[j] || tfpig[j]) && bld[j] > 0) { pos = j; break; }
else if (op == "ZP" && pig[j] == "FP" && iden[j] && bld[j] > 0) { pos = j; break; }
else if (op == "FP" && pig[j] == "ZP" && iden[j] && bld[j] > 0) { pos = j; break; }
return pos;
} // 找到对应种类的猪所要找到的杀的对象,没找到返回-1。
bool find_to_kill(string op, int x) {
bool can = false;
string nxt = pig[rpig[x]];
if (op == "MP" && (nxt == "FP" && iden[rpig[x]] || tfpig[rpig[x]])) can = true;
else if (op == "ZP" && nxt != "MP" && iden[rpig[x]] && pig[rpig[x]] == "FP") can = true;
else if (op == "FP" && nxt != "FP" && (rpig[x] == 1 || iden[rpig[x]] && pig[rpig[x]] == "ZP")) can = true;
return can;
}
void play(int x) { // 模拟
In(x, 2);
bool ok = false, use_K = false;
for (int i = 1; i <= tot[x]; i++) {
if (flag[x][i]) continue;
char now = c[x][i];
switch (now) {
case 'P': peach(x); break;
case 'K':
if (find_to_kill(pig[x], x) && (!arm[x] && !use_K || arm[x])) { kill(x, rpig[x]), use_K = true; }
break;
case 'F':
if (pig[x] == "FP") fight(x, 1);
else if (find(pig[x], x) != -1) fight(x, find(pig[x], x));
break;
case 'N': nanzhu(x); break;
case 'W': wanjian(x); break;
case 'Z': Arm(x); break;
}
if (dead[x]) break;
}
}
void work() {
int i = 0;
while (fpig && bld[1] > 0) {
i = i % n + 1;
if (dead[i]) continue;
else play(i);
}
}
int main() {
Read();
work();
Print();
return 0;
}
100 100 100 分
其实加入了无懈可击,只不过是给代码贴了一点补丁,只要理解了就能很快写出来,推荐用dfs的方式写,个人认为会更好些一些。。。
这里就不贴代码了,请读者自行完成。