csp賽前刷題篇 圖論篇 [USACO07NOV]Cow Relays G
阿新 • • 發佈:2020-10-11
https://www.luogu.com.cn/problem/P2886
看一眼本題,Floyd演算法。那麼什麼是Floyd演算法呢??
Floyd
Floyd是一種最短路演算法,適用於點數較少的圖
Floyd的本質是動態規劃,它的狀態定義以及轉移:
設f[i][j]f[i][j]為ii到jj的最短距離
f[i][j]=min(f[i][j],f[i][k]+f[k][j])f[i][j]=min(f[i][j],f[i][k]+f[k][j])
程式碼實現:
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j= 1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
下面讓我們魔改一下
令f[k,i,j]表示 從i經過k條邊到達j 原Floyd表達 從i 到j走1~k個點,最短路徑是多少。
魔改後 轉移方程 f[a+b,i,j]=min(f[a,i,k],f[b,i,k]),k=1~n。
d[a,i,k]中的k不是什麼第k條邊,而是表示從i走了a條邊(就是相當於走了a步)以後到達的結點k,因此這個k是在1~N之間的一個點。
這個轉移方程表示從i到j走a+b(x)條邊,等於在所有從i走a條邊到k,再從k走b(x−a) 條邊到j中取最小值。
這樣我們要求的是經過N條邊的最短路,最開始輸入的每一個都是1條邊(經過一條邊的兩個點的距離),那麼我們要得到經過N條邊就可以按照上述的方程,加N-1次(d[2,i,j] = d[1,i,k] + d[1,k,j])
同時,這裡可以用快速冪來優化。
這裡有一百條邊,用兩百個點,給到1000.所以要離散化一下。
離散化
即在不i改變資料相對大小的前提下,對資料進行相應的縮小。通常使用STL演算法離散化操作。
步驟為:排序,去重,lower bount。
程式碼如下:
sort(sub_a,sub_a+n);
int size=unique(sub_a,sub_a+n)-sub_a;//size為離散化後元素個數
for(i=0;i<n;i++) a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k為b[i]經離散化後對應的值
本題程式碼如下
#include<algorithm> #include<iostream> #includeView Code<cstring> #include<queue> #include<cstdio> #define N 0x3f3f using namespace std; int n, rt; int head[N], cnt; struct point { int next, to; }a[N * 4]; void add(int u, int v) { a[++cnt].to = v; a[cnt].next = head[u]; head[u] = cnt; } int f[N], dep[N], lea[N], num, sum[N]; bool vis[N]; void dfs(int now, int fa) { f[now] = fa; dep[now] = dep[fa] + 1; bool flag = 0; for (int i = head[now]; i; i = a[i].next) { int t = a[i].to; if (t == fa) continue; flag = 1; dfs(t, now); } if (!flag) lea[++num] = now; } bool cmp1(int a, int b) { return dep[a] == dep[b] ? a<b : dep[a]>dep[b]; } bool cmp2(int a, int b) { return sum[a] == sum[b] ? a<b : sum[a]>sum[b]; } int main() { cin >> n >> rt; for (int x, i = 1; i < n; ++i) { cin >> x; add(x, i); add(i, x); } dfs(rt, rt); sort(lea + 1, lea + num + 1, cmp1); vis[rt] = 1; for (int i = 1; i <= num; ++i) { int now = lea[i]; while (!vis[now]) { ++sum[lea[i]]; vis[now] = 1; now = f[now]; } } sort(lea + 1, lea + num + 1, cmp2); cout << rt; for (int i = 1; i <= num; ++i) cout << lea[i] << endl;; return 0; }