1 条题解

  • 0
    @ 2026-9-24 23:17:12

    前言

    题目传送门!

    更好的阅读体验?

    最短路应用。内容抄自某校课件。

    思路

    首先想到题目与最短路有关。

    假如 aa 到 bb 的最短路径长度是 xx,那么对于一个询问是否存在长度为 dd 的路径:

    • 如果 xx 和 dd 同奇偶,且 d≥xd \ge x,那么这个长度为 dd 的路径一定存在。

      因为可以从 aa 走 xx 步到 bb,然后走两步在 bb 与它相邻的点左右横跳,直到走的步数为 dd。

    • 但是如果 xx 与 dd 不同奇偶,路径就一定不存在吗?

    考虑下面的情况:

    随便两个点,奇偶的路径都是合法的。

    那么容易想到,我们可以维护从 aa 到 bb 的偶数步最短路径长度和奇数步最短路径长度。这一点显然可以用 Dijkstra 搞出来。

    然后我们根据 dd 的奇偶,判断对应的 aa 到 bb 的最短路径长度是否存在,存在的话并且长度小于等于 dd,那么长度为 dd 的路径就可以被构造出来。

    于是这题就差不多结束了。


    但是还有一组恶心的特判:

    3 1 1
    1 2
    3 3 2
    

    如果一个点是孤立的,那么怎么走都无解!

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int N = 5005, K = 1e6 + 5;
    struct Edge {int now, nxt;} e[N << 1];
    int head[N], cur;
    void add(int u, int v)
    {
    	e[++cur].now = v, e[cur].nxt = head[u];
    	head[u] = cur;
    }
    int dis[N][2]; //分奇偶
    bool inque[N];
    void spfa(int s)
    {
    	memset(dis, 0x3f, sizeof dis);
    	memset(inque, false, sizeof inque);
    	queue <int> q;
    	q.push(s), inque[s] = true, dis[s][0] = 0;
    	while (!q.empty())
    	{
    		int u = q.front();
    		q.pop(), inque[u] = false;
    		for (int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].now;
    			if (dis[u][0] + 1 < dis[v][1])
    			{
    				dis[v][1] = dis[u][0] + 1;
    				if (!inque[v]) inque[v] = true, q.push(v);
    			}
    			if (dis[u][1] + 1 < dis[v][0])
    			{
    				dis[v][0] = dis[u][1] + 1;
    				if (!inque[v]) inque[v] = true, q.push(v);
    			}
    		}
    	}
    }
    struct Query {int id, v, w;};
    vector <Query> query[N];
    bool ans[K];
    int main()
    {
    	//ios::sync_with_stdio(false);
    	int n, m, k;
    	scanf("%d%d%d", &n, &m, &k);
    	while (m--)
    	{
    		int u, v;
    		scanf("%d%d", &u, &v);
    		add(u, v), add(v, u);
    	}
    	for (int i = 1; i <= k; i++)
    	{
    		int u, v, w;
    		scanf("%d%d%d", &u, &v, &w);
    		query[u].push_back((Query){i, v, w});
    	}
    	for (int u = 1; u <= n; u++)
    		if (!query[u].empty() && head[u]) //特别注意!如果这个点是孤立的,怎么走都是无解
    		{
    			spfa(u);
    			for (Query t : query[u]) ans[t.id] = (t.w >= dis[t.v][t.w & 1]);
    		}
    	for (int i = 1; i <= k; i++)
    		if (ans[i]) puts("TAK"); else puts("NIE");
    	return 0;
    }
    

    希望能帮助到大家!

    • 1

    [POI 2013] MOR-Tales of seafaring海上故事

    信息

    ID
    5082
    时间
    1500ms
    内存
    228MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者