HDU 4479 权递增的最短路问题

题目大意:

找一条节点 1 到节点 N 的最短路,保证这条路上每一条边都比前一条边长

dp[i] 表示在当前状态下1到i的最小值

先将所有边根据边的长度排一个序,再每次取出同一段相同长度的边去更新当前图中的每一个点可以更新的dp值,当然我们不能不能因为这相同的边长相互影响,所以不能边找边的同时边松弛dp值,因为可能 1-2:1  2-3:1,也就是说第一次其实不能由1到3这个点,但是你先更新1-2,那么2-3会因为2的dp值存在而可以松弛,所以,先找到所有可行的能进行迟缓的边记录在rec[]数组中,再把里面所有的边弛缓一遍

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 using namespace std;
 6 const int N = 10005;
 7 typedef long long LL;
 8 LL dp[N];
 9 int n , m , k;
10
11 struct Path{
12     int x,y,d;
13     bool operator<(const Path &m)const{
14         return d < m.d;
15     }
16 }p[100005];
17
18 struct Rec{
19     int x,y;
20     LL d;
21     Rec(int x=0,int y=0,LL d=0):x(x),y(y),d(d){}
22 }rec[100005];
23
24 void update(int l , int r)
25 {
26     int t = 0;
27
28     for(int i=l;i<=r;i++){
29         int u = p[i].x , v = p[i].y;
30         if(dp[u] >= 0 && (dp[v] > dp[u] + p[i].d || dp[v] < 0))
31         {
32             rec[t++] = Rec(u,v, dp[u] + p[i].d);
33         }
34         if(dp[v] >= 0 && (dp[u] > dp[v] + p[i].d || dp[u] < 0))
35         {
36             rec[t++] = Rec(v,u, dp[v] + p[i].d);
37         }
38     }
39
40     for(int i=0;i<t;i++){
41         int u = rec[i].x , v = rec[i].y;
42         if(dp[v] > rec[i].d || dp[v] < 0)
43         {
44             dp[v] = rec[i].d;
45         }
46     }
47 }
48
49 void add_edge(int x,int y,int d)
50 {
51     p[k].x = x , p[k].y = y , p[k++].d = d;
52 }
53
54 void solve()
55 {
56     sort(p,p+k);
57     memset(dp,-1,sizeof(dp));
58     dp[1] = 0;
59     int l=0;
60     for(int r=1 ; r<k;r++){
61         if(p[r].d != p[r-1].d){
62             update(l , r-1);
63             l=r;
64         }
65     }
66     update(l,k-1);
67     if(dp[n] < 0)
68         puts("No answer");
69     else
70         printf("%I64d\n",dp[n]);
71 }
72
73 int main()
74 {
75    // freopen("test.in","rb",stdin);
76
77     int T,a,b,d;
78     scanf("%d",&T);
79     while(T--){
80         scanf("%d%d",&n,&m);
81
82         k=0;
83         memset(G , -1 , sizeof(G));
84         for(int i=0;i<m;i++){
85             scanf("%d%d%d",&a,&b,&d);
86             add_edge(a,b,d);
87         }
88         solve();
89     }
90     return 0;
91 }
时间: 2024-12-17 21:21:09

HDU 4479 权递增的最短路问题的相关文章

HDU 6464 /// 权值线段树

题目大意: 共Q次操作 操作有两种 操作一 在序列尾部加入f[i]个s[i] 操作二 查询序列第f[i]小到第s[i]小之间的总和 离线操作 把序列内的值离散化 然后利用离散化后的值 在线段树上对应权值操作 权值线段树维护权值对应的值的个数和总和 查询 用s[i]的前缀和减去f[i]-1的前缀和 具体看注释 #include <bits/stdc++.h> using namespace std; #define LL long long #define INF 0x3f3f3f3f #def

HDU 1087 最大递增子序列

Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 56574    Accepted Submission(s): 26248 Problem Description Nowadays, a kind of chess game called “Super Jumping!

HDU 3038(权值并查集)

How Many Answers Are Wrong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 21469    Accepted Submission(s): 7404 Problem Description TT and FF are ... friends. Uh... very very good friends -____

hdu 1087 最大递增和

思路和LIS差不多,dp[i]为i结尾最大值 #include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <

hdu 6703 权值线段树

题意: 给出一个1-n的全排列   a 操作1:修改a[pos] 为 a[pos]+1000000 操作2: 问k的所有后继中(包括k) 最小的 且与a[1]-a[r]均不相等的数是多少 n<=1e5 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #de

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边. 构造最小生成树,要解决以下两个问题: (1).尽可能选取权值小的边,但不能构成回路(也就是环). (2).选取n-1条恰当的边以连接网的n个顶点. Prim算法的思想: 设G = (V,E)是连通带权图,V = {1,2,-,n}.先任选一点(一般选第一个点),首

HDU 4313 Matrix(并查集|最小生成树变种)

 题意:给你一个有n(2<=n<=100000)个节点的树,树中每条边都有一个权值.然后再给你k(2<=k<=n)个点,表示这些点上有一个机器人.最后让你删去一些边使任意两个机器人都不能互达,且所删边的权值之和要最小. 思路:不难发现,最后一定要正好去掉k-1条边才能使他们互不连通,对于这k-1条边我们希望他们的权值之和最小, 更进一步,我们希望选取的每条边都尽量小. 正常来想,应该是边权递增排序,每次去掉一条边,看是否不连通的数目加一,但这样做太麻烦. 可以反向来想,把边递减

Bellman-Ford(可解决负权边)--时间复杂度优化

Bellman-Ford 可解决带有负权边的最短路问题 解决负权边和Dijkstra相比是一个优点,Bellman-Ford的核心代码只有4行:: u[],v[],w[] 分别存一条边的顶点.权值,dis[]存从 1 源点到各个顶点的距离 for(i=1;i<=n-1;i++) for(j=1;j<=m;j++) if(dis[v[i]] > dis[u[i]]+w[i]) dis[v[i]] = dis[u[i]]+w[i]; 愿过程: 循环n-1次,把每个顶点每条边都松弛: 优化方法

51nod 1274 最长递增路径(DP)

一开始自己想了一种跑的巨慢..写了题解的做法又跑的巨快..一脸懵逼 显然要求边权递增就不可能经过重复的边了,那么设f[i]为第i条边出发能走多远就好了,这是我一开始的写法,可能dfs冗余状态较多,跑的极慢 #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include