专栏文章
题解:P3557 [POI 2013] GRA-Tower Defense Game
P3557题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio9mea0
- 此快照首次捕获于
- 2025/12/02 15:37 3 个月前
- 此快照最后确认于
- 2025/12/02 15:37 3 个月前
给定一个图,选定不多于 个点,使得图中每个点都离某一个选定的点距离不多于 。无需最小化选点数量。保证可以选定不多于 个点,使得图中每个点都离某一个选定的点距离不多于 。
这是错误做法
既然有了后面的保证,那么就考虑后面那个题怎么做?
省流:NP 完全的,目前没有发现多项式时间做法。实际上如果你找到了多项式复杂度做法,或者证明了不存在,那么快去领图灵奖吧!
好消息,这个问题是一个经典的问题。坏消息:

当然,如果你不相信 AI,那么百度百科:

那么我们就需要使用下面的条件了。大胆贪心!每次选出一个没有满足条件的点,选择这个点!
这对吗?这能过,实现方法后面讲。这真的对吗?
考虑证明。不妨设我们的解的点集为 ,而条件中的问题的答案为 。根据定义,对于任意一个不在 中的,邻居中都至少有一个 中的点。所以,对于每个 中的点,我们都能找到最多一个 中的点与之对应(就是相邻点或者自身,唯一性是因为两个 中的点距离必然至少为 ),所以 。证毕!
实现方法
DFS。从小到大枚举每个点,如果没有被标记过则 dfs(不考虑标记,考虑标记正确性就不对了)将所有与其距离不多于 的点标记上并将自身加入答案中。
看起来一个菊花图就能卡掉是吧!实际上菊花图上选任意一个节点都可以完成。你是卡不掉的。
时间复杂度证明就是,每个点最多和被选中的点相邻一次,也就是只会被遍历一次所有邻居,总时间复杂度就是度数之和 ,加上枚举所有点的复杂度 。
代码&提交记录
Fun fact:代码和 没有关系。
CPP#include <cstdio>
#include <vector>
using namespace std;
vector<int> web[500005];
bool vis[500005];
void dfs(int u, int d = 0) // d = depth = 深度
{
vis[u] = true;
if (d == 2) return;
for (int v : web[u])
{
dfs(v, d + 1);
}
}
int main()
{
int n, m;
scanf("%d%d%*d", &n, &m); // 冷门小技巧:%*d 可以跳过一个数字,%*c %*s 等同理
for (int i = 1; i <= m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
web[x].push_back(y);
web[y].push_back(x);
}
vector<int> ans;
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
ans.push_back(i);
dfs(i);
}
}
printf("%d\n", ans.size());
for (int i : ans)
{
printf("%d ", i);
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...