51nod 1274 最长递增路径【dp】

题目来源:  Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
一个无向图,可能有自环,有重边,每条边有一个边权。你可以从任何点出发,任何点结束,可以经过同一个点任意次。但是不能经过同一条边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);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值