1. 程式人生 > 實用技巧 >維修道路(repair)

維修道路(repair)

維修道路(repair)

時間限制:1 Sec記憶體限制:128 MB

題目描述

由於在十多年前道路改建時的突出貢獻,Bob被任命為維修道路的承包商, 他可以任意
選擇兩條路徑去修理。
Bob剛剛獲悉,這n個村莊相互連通,而且總共只有n-1條邊。
眾所周知,Bob修理這兩條道路得到的獲益是兩條路徑的長度的積, 所以當然他想最大
化他的獲益。
但是,Bob又不希望別人在背後說他壞話, 所以他希望這兩條路徑滿足以下兩個條件:
1.這兩條路徑都是某兩個村莊之間的最短路徑。(某兩個村莊就是路徑的起點和終點)
2.這兩條路徑不會經過同一個村莊。

輸入

第一行輸入n。 表示村莊個數。
接下來n-1行,每行兩個數,表示這兩個村莊之間有一條無向邊。

輸出

輸出獲益的最大值。

樣例輸入

4
1 2
2 3
3 4

7
1 2
1 3
1 4
1 5
1 6
1 7

6
1 2
2 3
2 4
5 4
6 4

樣例輸出

1
0
4

提示

1.選擇(1->2)和(3->4) Ans=1*1
2.不管怎麼選擇這兩條路徑,一定會經過 1
3.選擇(1->3)和(5->6) Ans=2*2=4


emmmm
其實不難
題意:在一棵樹上找到兩條不相交的路徑(不能有點重合), 並且是兩點之間的最短路徑
使這兩個路徑長度的乘積最大
可以發現,這兩條在樹上了路徑,肯定是兩個不同的部分中(因為他在樹上qwq)
那我們就列舉斷掉樹的一條邊,然後再分別求這兩個樹的直徑就是最優的答案了。

這個是O(n^2)的
有兩個點T掉了
怎麼辦呢
這個簡單,直接打表優化awa
我們直接分類討論,討論直徑是否斷開,如果不斷開,那麼結果是直徑長度與掛在直徑下面的子樹的直徑乘積。
設直徑的左右端點為A和B,斷開直徑的一條邊,那麼結果就是左邊某個點到A的長度和右邊某個點到B的長度,可以通過維護字首的和字尾,分別維護左邊到達A和右邊到達B的最長路。
直接引用題解

qwq

這個程式碼沒寫awa

O(n^2)的有qwq
奉上

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,tot=1,flag1,flag2,head[1000001
]; int sum,ret,ans,id; struct edge { int next,to; }e[1000001]; inline ll read() { char c=getchar();ll a=0,b=1; for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1; for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48; return a*b; } inline void add(int i,int j) { e[++tot].next=head[i]; e[tot].to=j; head[i]=tot; } void dfs(int x,int fa,int dis,int opt) { if(opt==1&&x==flag2) return; if(opt==2&&x==flag1) return; if(dis>ret)ret=dis,id=x; for(int i=head[x];i!=0;i=e[i].next) { int u=e[i].to; if(u==fa)continue; dfs(u,x,dis+1,opt); } } int main() { n=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } for(int i=2;i<=tot;i+=2) { ret=0;sum=0;id=0; flag1=e[i].to; flag2=e[i^1].to; dfs(flag1,flag2,0,1); ret=0; dfs(id,flag2,0,1); sum=ret,ret=0,id=0; dfs(flag2,flag1,0,2); ret=0; dfs(id,flag1,0,2); sum*=ret; ans=max(ans,sum); } cout<<ans<<endl; return 0; }