最长递增路径
题目链接:51nod 1274
题目大意
给你一个无向图,边有边权,然后要你找到一条路径使得可以有重复点但是不会有重复边,走过的边权值严格单调递增。
然后问你这条路径的最长长度。
思路
教练任务。
看到严格单调递增,而且是边权,不难想到通过边权来 DP。
设
f
i
f_i
fi 为走到
i
i
i 点的路径的最长长度。
然后考虑边权从小到大枚举边,然后直接转移。
(然后要注意的是边权一样的要一起转移,先把之前的状态记录下来,再用来转移)
代码
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50000 + 10;
struct node {
int x, y, w;
}a[N];
int n, m, f[N];
vector <int> tmp;
bool cmp(node x, node y) {//按边权从小到大排序
return x.w < y.w;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].w);
}
sort(a + 1, a + m + 1, cmp);//排序
for (int L = 1, R; L <= m; L = R + 1) {
R = L; while (R < m && a[R + 1].w == a[L].w) R++;//提取出一段边权相同的区间
tmp.clear(); for (int i = L; i <= R; i++) tmp.push_back(f[a[i].x]), tmp.push_back(f[a[i].y]);
//先把转移要的值记录下来(因为你可能后面转移的时候会使得它们发生变化,就比如两个相同权值的边连着)
//这题是要严格上升序列,所以是不可以跟着转移的
int num = 0;
for (int i = L; i <= R; i++) {//转移
f[a[i].y] = max(f[a[i].y], tmp[num++] + 1);
f[a[i].x] = max(f[a[i].x], tmp[num++] + 1);
}
}
int ans = 0;//统计答案并输出
for (int i = 0; i < n; i++) ans = max(ans, f[i]);
printf("%d", ans);
return 0;
}