题解:P9287 [ROI 2018] Viruses
注意到,这是一道假扮成 OI 题的语文阅读理解题。
题意
有
每个时刻每个细胞都会感染恰好一个病毒。令当前细胞
在每个细胞心目中都有对每个病毒的能力的排名。即给定一个
细胞会互相攻击。当细胞
细胞们可以任意安排攻击顺序。当且仅当没有细胞可以被任意一名病毒感染时,游戏宣告结束。显然游戏的最终局面(
我们定义在某个游戏的最终局面里,一个病毒是「牛的」,这个病毒没有灭绝,即存在至少一个细胞感染了这个病毒。
你需要解决两个问题:
- 求哪些病毒是「稳定的」。一个病毒是稳定的,当且仅当这个病毒在所有游戏的最终局面里都是牛的。
- 求哪些病毒是「可行的」。一个病毒是稳定的,当且仅当这个病毒在至少一种游戏的最终局面里是牛的。
Part.1 「稳定的病毒」
考虑求解哪些病毒是「稳定的」。
我们断言病毒
我们考虑题目中描述的能够发生感染的条件:
当细胞
i 攻击细胞j 时,……,当细胞j 认为i 的病毒更强时,它会放弃自己现有的病毒,而感染更强的。
我们知道细胞
Part.2 「可行的病毒」
考虑求解哪些病毒是「可行的」。
首先以
根据题目描述,如果病毒
游戏结束的条件是不存在任何一对细胞可以攻击。那么如果病毒
这给我们的启发是,只有在当前局面里,细胞
所以我们现在要判断是否每个(在细菌
如何把病毒
把病毒
代码
int n, p, a[N][N], b[N][N];
// a[i][j] 表示在细菌 i 心目中第 j 强的病毒
// b[i][j] 表示在细菌 i 心目中第 j 个病毒的排名
bool st[N]; // 把在细菌 j 心目中比病毒 i 强的病毒标记
signed main() {
cin >> n;
for (int i = 1; i <= n; ++ i )
for (int j = 1; j <= n; ++ j ) {
cin >> a[i][j];
b[i][a[i][j]] = j;
}
vector<int> res;
cin >> p;
if (p == 1) {
for (int i = 1; i <= n; ++ i )
if (a[i][1] == i) res.push_back(i);
} else {
for (int i = 1; i <= n; ++ i ) { // 判断病毒 i 能否活下来
bool Alive = false; // 判断病毒 i 能否在任意一个细菌 j 中活下来
for (int j = 1; j <= n && !Alive; ++ j )
if (b[j][i] <= b[j][j]) { // 首先它要比细菌 j 中最初的病毒(病毒 j)要强,不然没机会
memset(st, 0, sizeof st);
for (int k = 1; k < b[j][i]; ++ k ) {
st[a[j][k]] = true; // 把在细菌 j 心目中比病毒 i 强的病毒标记
}
bool all_destroyed = true; // 判断在细菌 j 心目中比病毒 i 强的病毒标记是否都灭绝
for (int k = 1; k < b[j][i] && all_destroyed; ++ k ) {
int x = a[j][k]; // 取出一个在细菌 j 心目中比病毒 i 强的病毒
bool ok = false; // 判断是否存在一个没有标记的病毒,且在细菌 x 心目中比病毒 x 强
for (int l = 1; l < b[x][x] && !ok; ++ l )
if (!st[a[x][l]]) ok = true;
if (!ok) all_destroyed = false;
}
if (all_destroyed) Alive = true;
}
if (Alive) res.push_back(i);
}
}
cout << res.size() << '\n';
for (int v : res) cout << v << ' ';
return 0;
}