1. 程式人生 > >BZOJ1912 APIO2010 洛谷P3629 巡邏

BZOJ1912 APIO2010 洛谷P3629 巡邏

資金 AC size 包含 rip pan NPU img ++

Description:

在一個地區中有 n 個村莊,編號為 1, 2, ..., n。有 n – 1 條道路連接著這些村 莊,每條道路剛好連接兩個村莊,從任何一個村莊,都可以通過這些道路到達其 他任一個村莊。每條道路的長度均為 1 個單位。 為保證該地區的安全,巡警車每天要到所有的道路上巡邏。警察局設在編號 為 1 的村莊裏,每天巡警車總是從警察局出發,最終又回到警察局。 下圖表示一個有 8 個村莊的地區,其中村莊用圓表示(其中村莊 1 用黑色的 圓表示),道路是連接這些圓的線段。為了遍歷所有的道路,巡警車需要走的距 離為 14 個單位,每條道路都需要經過兩次。

技術分享圖片

為了減少總的巡邏距離,該地區準備在這些村莊之間建立 K 條新的道路, 每條新道路可以連接任意兩個村莊。兩條新道路可以在同一個村莊會合或結束 (見下面的圖例(c))。 一條新道路甚至可以是一個環,即,其兩端連接到同一 個村莊。 由於資金有限,K 只能是 1 或 2。同時,為了不浪費資金,每天巡警車必須 經過新建的道路正好一次。 下圖給出了一些建立新道路的例子:

技術分享圖片

在(a)中,新建了一條道路,總的距離是 11。在(b)中,新建了兩條道路,總 的巡邏距離是 10。在(c)中,新建了兩條道路,但由於巡警車要經過每條新道路 正好一次,總的距離變為了 15。 試編寫一個程序,讀取村莊間道路的信息和需要新建的道路數,計算出最佳 的新建道路的方案使得總的巡邏距離最小,並輸出這個最小的巡邏距離。

Input :

第一行包含兩個整數 n, K(1 ≤ K ≤ 2)。接下來 n – 1 行,每行兩個整數 a, b, 表示村莊 a 與 b 之間有一條道路(1 ≤ a, b ≤ n)。

Output:

輸出一個整數,表示新建了 K 條道路後能達到的最小巡邏距離。

思路:K = 1時,求出樹的直徑L,然後把兩端加一條邊即可,答案就是2 * (n - 1) - L + 1

K = 2時,兩個環的重疊部分會被巡邏兩次,所以當求出直徑L1的時候對直徑上的邊取反然後再求一遍直徑L2就可以了(因為L2如果經過這個L1取反的部分,說明兩個部分重疊,減掉L1之後重疊部分就只經過一次了,減掉(L2 - 1)相當於把重疊的部分加回來,變成“需要經過兩次”),答案就是2 * (n - 1) - (L1 - 1)- (L2 - 1)

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10; int head[N], now = 1; struct edges{ int to,next,w; }edge[N<<1]; void add(int u ,int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;} int n, k, dep[N], pre[N], pos1, pos2, d[N], L1, L2; void dfs1(int x,int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; dep[v] = dep[x] + edge[i].w; dfs1(v, x); } if(dep[x] > dep[pos1]) pos1 = x; } void dfs2(int x,int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; d[v] = d[x] + edge[i].w; pre[v] = i; dfs2(v, x); } if(d[x] > d[pos2]) pos2 = x; } void work(int x){ if(x == 0) return ; int tmp = pre[x]; edge[tmp].w = edge[tmp ^ 1].w = -1; work(edge[tmp ^ 1].to); } void dp(int x, int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; dp(v, x); L2 = max(L2, d[x] + d[v] + edge[i].w); d[x] = max(d[x], d[v] + edge[i].w); } } int main(){ scanf("%d%d",&n, &k); int x, y; for(int i = 1; i < n; i++){ scanf("%d%d",&x,&y); add(x, y, 1); add(y, x, 1); } dfs1(1, -1); dfs2(pos1, -1); work(pos2); L1 = d[pos2]; if(k == 1){ printf("%d\n",2 * n - L1 - 1); return 0; } /* for(x = 1; x <= n; x++){ cout<<x<<": "; for(int i = head[x]; i; i = edge[i].next) cout<<edge[i].to<<" "<<"("<<edge[i].w<<") "; cout<<endl; }*/ memset(d,0,sizeof(d)); dp(1, -1); printf("%d\n",2 * n - L1 - L2); return 0; }
View Code

BZOJ1912 APIO2010 洛谷P3629 巡邏