new file: P2482.cpp

This commit is contained in:
hanyixuanten
2026-07-15 16:34:53 +08:00
parent f1d2fa6984
commit e37671a66a
+478
View File
@@ -0,0 +1,478 @@
#include <bits/stdc++.h>
using namespace std;
int n, m;
char js[15]; // 角色:M主猪, Z忠猪, F反猪
char p[15][10005]; // 手牌
int l[15], r[15]; // 手牌左右边界(闭区间)
vector<char> dui; // 牌堆(尾部为堆顶)
int stre[15]; // 体力值
int fro[15], nex[15]; // 双向链表,用于存活角色遍历
bool zgln[15]; // 是否装备诸葛连弩
bool tiao[15]; // 是否已跳身份(忠/反表明)
bool lei[15]; // 主猪的类反猪标记
char last_card = 'P'; // 牌堆最后一张(初始为桃,避免空堆摸到空字符)
inline char read()
{
char ch = getchar();
while (ch < 'A' || ch > 'Z')
ch = getchar();
return ch;
}
void init()
{
scanf("%d %d\n", &n, &m);
for (int i = 0; i < n; ++i)
{
js[i] = read();
read(); // 跳过空格
for (int j = 0; j < 4; ++j)
p[i][j] = read();
stre[i] = 4;
l[i] = 0;
r[i] = 3;
fro[i] = (i == 0) ? (n - 1) : (i - 1);
nex[i] = (i + 1) % n;
}
for (int i = 0; i < m; ++i)
dui.push_back(read());
reverse(dui.begin(), dui.end()); // 牌堆尾部为堆顶
}
int pd()
{
bool fp_alive = false;
for (int i = 0; i < n; ++i)
if (js[i] == 'F' && stre[i] > 0)
{
fp_alive = true;
break;
}
if (stre[0] <= 0)
return 2; // FP胜
if (!fp_alive)
return 1; // MP胜
return 0; // 未结束
}
void mp(int now, int cnt)
{
while (cnt--)
{
if (!dui.empty())
{
last_card = dui.back();
dui.pop_back();
}
p[now][++r[now]] = last_card;
}
}
void dealdead(int now, int from)
{
// 濒死求桃
if (stre[now] <= 0)
{
for (int j = l[now]; j <= r[now]; ++j)
if (p[now][j] == 'P')
{
stre[now]++;
p[now][j] = 0;
if (stre[now] > 0)
break;
}
}
if (stre[now] <= 0)
{
// 死亡处理:从存活链表中移除
if (now != 0)
{
nex[fro[now]] = nex[now];
fro[nex[now]] = fro[now];
}
// 奖惩:仅在游戏未结束时执行
if (pd() == 0)
{
if (js[now] == 'F')
{
mp(from, 3);
}
else if (js[now] == 'Z' && js[from] == 'M')
{
// 主猪弃掉所有手牌和装备
for (int j = l[from]; j <= r[from]; ++j)
p[from][j] = 0;
l[from] = 0;
r[from] = -1;
zgln[from] = false;
}
}
// 死亡猪自己的手牌全部弃置
for (int j = l[now]; j <= r[now]; ++j)
p[now][j] = 0;
l[now] = 0;
r[now] = -1;
zgln[now] = false;
}
}
/* ---------- 无懈可击相关函数 ---------- */
int findJ(int now)
{
for (int i = l[now]; i <= r[now]; ++i)
if (p[now][i] == 'J')
return i;
return -1;
}
void useJ(int now)
{
int pos = findJ(now);
if (pos != -1) p[now][pos] = 0;
}
// 判断 now 是否会对 target 使用无懈可击,isProtect=true 表示献殷勤,false 表示表敌意
bool canUseJ(int now, int target, bool isProtect)
{
if (isProtect)
{
// 献殷勤:不会对未表明身份的猪(包括自己),主猪视为已表明
if (!(tiao[target] || js[target] == 'M')) return false;
if (js[now] == 'M')
return (target == now) || (js[target] == 'Z' && tiao[target]);
else if (js[now] == 'Z')
return (target == 0) || (js[target] == 'Z' && tiao[target]);
else if (js[now] == 'F')
return (js[target] == 'F' && tiao[target]);
}
else
{
// 表敌意
if (js[now] == 'M')
return (js[target] == 'F' && tiao[target]);
else if (js[now] == 'Z')
return (js[target] == 'F' && tiao[target]);
else if (js[now] == 'F')
return (target == 0) || (js[target] == 'Z' && tiao[target]);
}
return false;
}
// 询问链:当前牌的使用者 user,目标 targetisProtect 表示当前牌是保护(true)还是攻击(false)
// 返回 true 表示当前牌被无懈可击抵消
bool askWJ(int user, int target, bool isProtect)
{
if (pd() != 0) return false;
int cur = user;
do
{
if (stre[cur] <= 0) { cur = nex[cur]; continue; }
if (findJ(cur) == -1) { cur = nex[cur]; continue; }
bool willProtect;
int jTarget;
if (!isProtect) // 当前牌是攻击(锦囊),出J是保护
{
willProtect = true;
jTarget = target;
}
else // 当前牌是保护(J),出J是攻击
{
willProtect = false;
jTarget = user;
}
if (canUseJ(cur, jTarget, willProtect))
{
useJ(cur); // 弃置最左的J
// 跳身份处理
if (willProtect) // 献殷勤
{
if (js[cur] == 'Z' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget])))
tiao[cur] = true, lei[cur] = false;
else if (js[cur] == 'F' && (js[jTarget] == 'F' && tiao[jTarget]))
tiao[cur] = true, lei[cur] = false;
// 主猪献殷勤不需跳身份
}
else // 表敌意
{
if (js[cur] == 'Z' && js[jTarget] == 'F' && tiao[jTarget])
tiao[cur] = true, lei[cur] = false;
else if (js[cur] == 'F' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget])))
tiao[cur] = true, lei[cur] = false;
// 主猪表敌意给已跳反猪,若目标有类反标记则清除
if (js[cur] == 'M' && js[jTarget] == 'F' && tiao[jTarget])
lei[jTarget] = false;
}
// 递归:询问是否有人无懈可击这张J
if (!askWJ(cur, jTarget, willProtect)) // 这张J没有被抵消 → 成功抵消当前牌
return true;
// 否则J被抵消,继续循环询问下一个猪
}
cur = nex[cur];
} while (cur != user);
return false;
}
/* ---------- 锦囊结算 ---------- */
void NW(int now, char KD) // 南蛮/万箭
{
int cur = nex[now];
while (cur != now)
{
if (stre[cur] <= 0) { cur = nex[cur]; continue; }
// 无懈可击抵消此次范围伤害
if (askWJ(now, cur, false))
{
cur = nex[cur];
continue;
}
bool kou = true;
for (int j = l[cur]; j <= r[cur]; ++j)
if (p[cur][j] == KD)
{
p[cur][j] = 0;
kou = false;
break;
}
if (kou)
{
stre[cur]--;
if (cur == 0 && !tiao[now])
lei[now] = 1;
dealdead(cur, now);
if (pd()) return;
}
cur = nex[cur];
}
}
void do_K(int now, int obj)
{
// 跳身份
if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj])
tiao[now] = true, lei[now] = false;
if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj])))
tiao[now] = true, lei[now] = false;
bool kou = true;
for (int i = l[obj]; i <= r[obj]; ++i)
if (p[obj][i] == 'D')
{
p[obj][i] = 0;
kou = false;
break;
}
if (kou)
{
stre[obj]--;
dealdead(obj, now);
}
}
bool haveK(int now)
{
for (int i = l[now]; i <= r[now]; ++i)
if (p[now][i] == 'K')
{
p[now][i] = 0;
return true;
}
return false;
}
void do_F(int now, int obj)
{
// 跳身份
if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj])
tiao[now] = true, lei[now] = false;
if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj])))
tiao[now] = true, lei[now] = false;
// 无懈可击抵消决斗
if (askWJ(now, obj, false))
return; // 决斗无效
bool turn = false; // false=obj先出杀
while (true)
{
int cur = turn ? now : obj;
int opp = turn ? obj : now;
if (js[cur] == 'Z' && js[opp] == 'M')
break;
if (haveK(cur))
turn = !turn;
else
break;
}
if (turn)
{
stre[now]--;
dealdead(now, obj);
}
else
{
stre[obj]--;
dealdead(obj, now);
}
}
void cp(int now)
{
bool usedK = false;
int F_target = -1;
while (pd() == 0 && stre[now] > 0)
{
int pos = -1;
for (int i = l[now]; i <= r[now]; ++i)
{
if (p[now][i] == 0) continue;
char c = p[now][i];
if (c == 'P' && stre[now] < 4)
{
pos = i; break;
}
if (c == 'Z')
{
pos = i; break;
}
if (c == 'N' || c == 'W')
{
pos = i; break;
}
if (c == 'K')
{
int obj = nex[now];
if (stre[obj] > 0)
{
bool ok = false;
if (js[now] == 'M')
ok = (js[obj] == 'F' && tiao[obj]) || (!tiao[obj] && lei[obj]);
else if (js[now] == 'Z')
ok = (js[obj] == 'F' && tiao[obj]);
else if (js[now] == 'F')
ok = (obj == 0) || (js[obj] == 'Z' && tiao[obj]);
if (ok && (!usedK || zgln[now]))
{
pos = i; break;
}
}
}
if (c == 'F')
{
int obj = -1;
if (js[now] == 'M')
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if ((js[j] == 'F' && tiao[j]) || (!tiao[j] && lei[j]))
{ obj = j; break; }
}
}
else if (js[now] == 'Z')
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if (js[j] == 'F' && tiao[j])
{ obj = j; break; }
}
}
else if (js[now] == 'F')
{
if (stre[0] > 0) obj = 0;
else
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if (js[j] == 'M' || (js[j] == 'Z' && tiao[j]))
{ obj = j; break; }
}
}
}
if (obj != -1)
{
pos = i;
F_target = obj; // 保存目标
break;
}
}
// 跳过 J(无懈可击不能主动使用)
}
if (pos == -1) break;
char card = p[now][pos];
p[now][pos] = 0;
if (card == 'P')
{
stre[now]++;
}
else if (card == 'Z')
{
zgln[now] = true;
}
else if (card == 'N')
{
NW(now, 'K');
if (pd()) break;
}
else if (card == 'W')
{
NW(now, 'D');
if (pd()) break;
}
else if (card == 'K')
{
do_K(now, nex[now]);
usedK = true;
if (pd()) break;
}
else if (card == 'F')
{
if (F_target != -1 && stre[F_target] > 0)
{
do_F(now, F_target);
if (pd()) break;
}
F_target = -1;
}
}
}
int main()
{
init();
for (int i = 0; pd() == 0; i = nex[i])
{
if (stre[i] <= 0) continue;
mp(i, 2);
cp(i);
}
printf("%s\n", pd() == 1 ? "MP" : "FP");
for (int i = 0; i < n; ++i)
{
if (stre[i] <= 0)
printf("DEAD\n");
else
{
bool first = true;
for (int j = l[i]; j <= r[i]; ++j)
if (p[i][j] != 0)
{
if (!first) printf(" ");
printf("%c", p[i][j]);
first = false;
}
printf("\n");
}
}
return 0;
}