小智的旅行(Bridge)51nod 提高组试题
题目描述
小智最喜欢旅行了,这次,小智来到了一个岛屿众多的地方,有N座岛屿,编号为0到N-1,岛屿之间 由一些桥连接,可以从桥的任意一端到另一端,由于岛屿可能比较大,所以会出现一些桥连接的是同 一个岛屿,岛屿之间也可能有多座桥连接,每条桥有一个长度,小智有一个习惯,每次走过的桥都必 须严格比之前走的桥长度长,小智可以从任意一个岛屿出发,任意一个岛屿结束,现在小智想知道最 多能走过多少条桥?
输入格式
第一行两个数N和M,分别表示岛屿个数和桥的个数 接下来M行,每行三个数a,b,c,表示岛屿a和b之间由一条长度为c的桥连接。
输出格式
一个数表示最多经过的桥的数量
咋一看,这道题好像有点迷。从普通的最小生成树、最短路、DFS等似乎无法下手。于是,考虑DP。
首先,设计状态: 设 dp[i] 表示第 i 个点最多的边。那么,如果我们能够走某一条边,即有:
dp[u] = max( dp[u], dp[v] + 1). dp[v] = max(dp[v], dp[u] + 1);
问题来了,如何确保我们的边可以走? 建图似乎很麻烦。
所以,我们直接排序!
将边按从小到大排序,那么就可以保证依次递增,我们就可以走了。
上代码:
#include <bits/stdc++.h> using namespace std; #define N 1000010 #define isdigit(c) ((c) >= '0' && (c) <= '9') inline int read(){ int x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-')s = -1; c = getchar(); } while(isdigit(c)){ x = (x << 1) + (x << 3) + (c ^ '0'); c = getchar(); } return x * s; } inline int max(int a, int b){ return a > b ? a : b; } struct node{ int u, v, w; } t[N]; int dp[N], temp[N]; bool cmp(node a, node b){ return a.w < b.w; } int main(){ int n = read(), m = read(); for(int i = 0;i < m; i++) t[i].u = read() + 1, t[i].v = read() + 1, t[i].w = read(); sort(t, t + m, cmp); int last = -1; dp[0] = 1; for(int i = 0;i < m; i++){ if(t[i].w != t[i + 1].w){ for(int j = last + 1; j <= i; j++){ int u = t[j].u, v = t[j].v; temp[u] = dp[u]; temp[v] = dp[v]; /*注意存临时变量,对应其原始dp值,因为后面u和v都要更改*/ } for(int j = last + 1;j <= i; j++){ int u = t[j].u, v = t[j].v; dp[u] = max(dp[u], temp[v] + 1); dp[v] = max(dp[v], temp[u] + 1); } last = i; } } int ans = -666; for(int i = 1;i <= n; i++) ans = max(ans, dp[i]); printf("%d\n", ans); return 0; }