题目大意:
找一条节点 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 ",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 }