一个无向图,可能有自环,有重边,每条边有一个边权。你可以从任何点出发,任何点结束,可以经过同一个点任意次。但是不能经过同一条边2次,并且你走过的路必须满足所有边的权值严格单调递增,求最长能经过多少条边。
以此图为例,最长的路径是:
3 -> 1 -> 2 -> 3 -> 2 或
3 -> 1 -> 2 -> 3 -> 4 长度为4。
Input
第1行:2个数N, M,N为节点的数量,M为边的数量(1 <= N <= 50000, 0 <= M <= 50000)。节点编号为0 至 N - 1。 第2 - M + 1行:每行3个数S, E, W,表示从顶点S到顶点E,有一条权值为W的边(0 <= S, E <= N - 1, 0 <= W <= 10^9)。
Output
输出最长路径的长度。
Input示例
6 8 0 1 4 1 2 3 1 3 2 2 3 5 3 4 6 4 5 6 5 0 8 3 2 7
Output示例
4
思路:
1、首先如果这个题的图是一个有向图的话。
那么我萌先把边按照从小到大排序,然后考虑dp,设定dp【i】表示到点i的最长距离。
那么有dp【v】=max(dp【v】,dp【u】+1);
2、接下来考虑,在无向图中应该如何处理?
显然需要有:
dp【v】=max(dp【v】,dp【u】+1);以及dp【u】=max(dp【u】,dp【v】+1);
然而因为dp【i】是一个数组,两个状态转移方程的先后顺序会有所影响。
那么考虑借助一个tmp【i】,记录没有更新过的时候的dp【i】;
那么此时就有:
dp【v】=max(dp【v】,tmp【u】+1);以及dp【u】=max(dp【u】,tmp【v】+1);
3、那么只要我们接下来对于一个权值的所有边进行一次处理即可(对于每一种权值进行统一处理)。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int u,v,w;
}e[500500];
int tmp[500500];
int dp[500500];
int cmp(node a,node b)
{
return a.w<b.w;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
memset(dp,0,sizeof(dp));
sort(e,e+m,cmp);
int pre=0;
for(int i=0;i<m;i++)
{
if(i==m-1||e[i].w<e[i+1].w)
{
for(int j=pre;j<=i;j++)
{
tmp[e[j].u]=dp[e[j].u];
tmp[e[j].v]=dp[e[j].v];
}
for(int j=pre;j<=i;j++)
{
int u=e[j].u;
int v=e[j].v;
dp[u]=max(dp[u],tmp[v]+1);
dp[v]=max(dp[v],tmp[u]+1);
}
pre=i+1;
}
}
int maxn=0;
for(int i=0;i<=n;i++)maxn=max(maxn,dp[i]);
printf("%d\n",maxn);
}
}