51nod最长递增路径:(还不错的图)
一个无向图,可能有自环,有重边,每条边有一个边权。你可以从任何点出发,任何点结束,可以经过同一个点任意次。但是不能经过同一条边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输出最长路径的长度。Sample 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
Sample Output
4
题意:在图中找最长路径,边权递增。
思路:不能直接以点为状态,因为不知道最后一次的长度。所以以边为最后状态,但是为了表面方向,就把每条边拆成两条。所以我直接用存边的信息来表示表示状态。
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> P; const int maxn=100010; int Laxt[maxn],Next[maxn],To[maxn],cost[maxn],cnt; P lin[maxn]; int l[maxn],r[maxn],dis[maxn],ans; void add(int u,int v,int c) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; cost[cnt]=c; } int main() { int N,M,u,v,c,i,j; scanf("%d%d",&N,&M); for(i=1;i<=M;i++){ scanf("%d%d%d",&l[i],&r[i],&c); add(l[i],r[i],c); add(r[i],l[i],c); lin[i]=P(c,i); } sort(lin+1,lin+M+1); for(i=1;i<=cnt;i++) dis[i]=1; for(i=1;i<=M;i++){ int Ln=lin[i].second,Ct=lin[i].first; for(j=Laxt[l[Ln]];j;j=Next[j]){ if(cost[j]>Ct) { dis[j]=max(dis[j],dis[2*Ln]+1); ans=max(ans,dis[j]); } } for(j=Laxt[r[Ln]];j;j=Next[j]){ if(cost[j]>Ct) { dis[j]=max(dis[j],dis[2*Ln-1]+1); ans=max(ans,dis[j]); } } } printf("%d\n",ans); return 0; } /* 2 4 0 1 1 1 0 2 0 1 3 1 0 4 */
It is your time to fight!