hdu 3440 House Man
https://vjudge.net/problem/HDU-3440
題意:
一個超人,他可以一個從一棟樓跳到另一棟樓。有一天,他為了加強技能,準備跳一系列的樓,他每次都從低的樓,跳到高的樓。他從最低的樓開始跳,但是他跳的水平距離是有限制的。
但是因為他是超人,所以他可以任意移動樓,而且他想他開始跳的樓與最後跳到的樓的距離最大。
他移動樓的時候有某些限制:
1.移動之後的樓的排列順序必須與輸入的順序相同。
2.必須滿足水平跳躍的距離的限制。
求這個最大距離,如果跳不到的話,輸出-1。
思路:
首先,超人跳的每棟樓的是按照高度遞增的順序來的,比如說i,j是高度相鄰的兩棟樓,那麽兩棟樓之間的距離肯定得滿足|xi - xj| <= d(限制),然後因為每棟樓之間的距離肯定是大於等於1的,所以Xi+1 - Xi >= 1,所以我們就可以找出一系列的不等式。我們需要通過這一系列的不等式找出加入最低的下標為u,最高的下標為v,那麽就是|Xu-Xv|的最大值,這樣的問題其實是一類叫做差分約束系統的問題。
差分約束系統是由最短路的松弛條件d[v] >= d[u] + w(u,v) 得來的,假設有不等式 Xi - Xj <= len,變形得到 Xi <= Xj + len,這樣就和最短路的松弛條件近似了,雖然說一個是大於等於,一個是小於等於,但是本質其實是一樣的,可以看成d[i] <= d[j] + w(j,i),那麽此時就可以建一條從j到i的邊,然後求出目標不等式的最大值,即相當於求圖中的最短路。
為什麽是最短路呢?比如有a - b <= 3 ,b - c <= 5,a - c <= 10,此時如果要求a - c的最大值,可以輕易地看出最大值是8,即是圖中的a到c的最短路,而不是10,本質是求所有不等式的交集,按照差分的約束條件 <= ,那麽就是求最小的那個。
還剩一個問題就是有沒有可能出現無解的情況,那就是圖中出現了負環,最短路可以無窮小,此時當然就無解了,比如b - a <= -3,c - b <= 2 ,a - c <= -5,那麽此時就是一個負環,此時求c - a的最小值,有c - a <= -1,c - a >= 5,此時就矛盾了,不存在最小值。
ok,回過來看這道題,根據題中的|xi - xj| <= d,我們可以建圖,去掉絕對值的方法就是邊從下標小的點指向下標大的點,因為輸入的樓之間是有先後順序的,之後因為每棟樓之間的距離必須大於等於1,所以Xi+1 - Xi >= 1(上面提到了,之後跑圖的話,就用spfa,因為dij無法判斷途中是否存在負環,spfa判斷途中是否存在負環的條件是一個點入隊的次數大於了n。
代碼:
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 8 struct edge 9 { 10 int from,to; 11 int w; 12 13 edge(){}; 14 edge(int x,int y,int z) 15 { 16 from = x; 17 to = y; 18 w = z; 19 } 20 }; 21 22 struct node 23 { 24 int hei; 25 int id; 26 27 bool operator < (const node &rhs) const 28 { 29 return this -> hei < rhs.hei; 30 } 31 } h[1005]; 32 33 vector<edge> edges; 34 vector<int> v[1005]; 35 36 void init(int n) 37 { 38 edges.clear(); 39 40 for (int i = 0;i <= n;i++) 41 v[i].clear(); 42 } 43 44 void adde(int from,int to,int w) 45 { 46 edge e = edge(from,to,w); 47 48 edges.push_back(e); 49 50 int sz = edges.size(); 51 52 v[from].push_back(sz - 1); 53 } 54 55 bool vis[1005]; 56 int d[1005]; 57 int cnt[1005]; 58 const int inf = 0x3f3f3f3f; 59 60 bool spfa(int s,int n) 61 { 62 memset(vis,0,sizeof(vis)); 63 memset(d,inf,sizeof(d)); 64 memset(cnt,0,sizeof(cnt)); 65 66 vis[s] = 1; 67 cnt[s] = 1; 68 69 queue<int> q; 70 71 q.push(s); 72 73 d[s] = 0; 74 75 while (!q.empty()) 76 { 77 int cur = q.front(); 78 q.pop(); 79 80 vis[cur] = 0; 81 82 for (int i = 0;i < v[cur].size();i++) 83 { 84 int id = v[cur][i]; 85 86 int to = edges[id].to; 87 88 if (d[to] > d[cur] + edges[id].w) 89 { 90 d[to] = d[cur] + edges[id].w; 91 92 if (!vis[to]) 93 { 94 q.push(to); 95 vis[to] = 1; 96 cnt[to]++; 97 98 if (cnt[to] > n) return 1; 99 } 100 } 101 } 102 } 103 104 return 0; 105 } 106 107 int main() 108 { 109 int t; 110 int cas = 0; 111 112 scanf("%d",&t); 113 114 while (t--) 115 { 116 printf("Case %d: ",++cas); 117 118 int n,dis; 119 120 scanf("%d%d",&n,&dis); 121 122 init(n); 123 124 for (int i = 1;i <= n;i++) 125 { 126 scanf("%d",&h[i].hei); 127 h[i].id = i; 128 } 129 130 for (int i = 1;i < n;i++) 131 { 132 adde(i+1,i,-1); 133 } 134 135 sort(h+1,h+n+1); 136 137 for (int i = 1;i < n;i++) 138 { 139 int x = min(h[i].id,h[i+1].id); 140 int y = max(h[i].id,h[i+1].id); 141 adde(x,y,dis); 142 } 143 144 int s = min(h[1].id,h[n].id); 145 int en = max(h[1].id,h[n].id); 146 147 bool f = spfa(s,n); 148 149 if (f) printf("-1\n"); 150 else printf("%d\n",d[en]); 151 } 152 153 return 0; 154 }
hdu 3440 House Man