P1137 旅行计划

解题思路

这道题目要求我们为每个城市i计算以i为终点的最长路径长度。由于题目中给出的道路方向表示城市x在城市y的西面(即x→y是有向边),所以可以将城市和道路建模为一个有向无环图(DAG)。在这种情况下,最长路径问题可以通过拓扑排序结合动态规划来解决。

关键点

  1. 拓扑排序:由于图是有向无环图,可以使用拓扑排序来确定节点的处理顺序,确保在处理一个节点时,所有指向它的节点都已经被处理过。

  2. 动态规划:定义f[i]表示以城市i为终点的最长路径长度。初始时,每个城市的f[i]为1(至少包含自己)。对于每条边x→y,更新f[y] = max(f[y], f[x] + 1),表示如果从x到y的路径更长,则更新y的最长路径。

  3. 输入处理:读取道路信息时,需要记录每个节点的入度(rd数组),并在拓扑排序中使用这些入度信息来确定处理顺序。

注意事项

  • 图的存储使用邻接表。

  • 需要初始化每个节点的f[i]为1,因为每个节点至少可以单独作为一个路径。

  • 拓扑排序时,使用队列来维护当前入度为0的节点,确保按正确的顺序处理节点。

代码注释

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10; // 定义最大节点数

vector<int> g[N]; // 邻接表,存储有向图的边关系
int n, m; // n表示城市数量,m表示道路数量
int rd[N]; // 存储每个节点的入度
int f[N]; // f[i]表示以城市i为终点的最长路径长度

// 拓扑排序函数,用于计算每个节点的最长路径长度
void topsort()
{
    queue<int> q; // 使用队列来维护当前入度为0的节点
    for(int i = 1; i <= n; i++)
    {
        if(rd[i] == 0){
            q.push(i); // 将入度为0的节点加入队列
        }
        f[i] = 1; // 初始化每个节点的最长路径长度为1(至少包含自己)
    }
    while(q.size()) // 当队列不为空时,继续处理
    {
        int x = q.front(); q.pop(); // 取出队首节点
        for(int i = 0; i < g[x].size(); i++) // 遍历所有从x出发的边
        {
            int y = g[x][i]; // y是x的后继节点
            rd[y]--; // 减少y的入度
            if(rd[y] == 0) q.push(y); // 如果y的入度为0,加入队列
            f[y] = max(f[y], f[x] + 1); // 更新y的最长路径长度
        }
    }
}

int main()
{
    cin >> n >> m; // 输入城市数量和道路数量
    for(int i = 1; i <= m; i++)
    {
        int x, y; cin >> x >> y; // 输入道路信息
        rd[y]++; // 增加y的入度
        g[x].push_back(y); // 添加有向边x→y
    }
    topsort(); // 执行拓扑排序和动态规划
    for(int i = 1; i <= n; i++) cout << f[i] << endl; // 输出每个城市的最长路径长度
    return 0;
}

 

posted @ 2025-06-11 20:50  CRt0729  阅读(21)  评论(0)    收藏  举报