這道題,調了我一晚上... 一直80分 >_<|| ...
考慮到幾點:
所以我們先列舉斷開直徑上的邊,然後分別找到斷開後兩棵子樹的直徑.
接著我們討論 \(dis_1,dis_2\) 最優情況.
其 \(dis\) 為其到子樹直徑較遠的一端.
如果 \(x_1,x_2\) 在子樹的直徑上,那麼顯然會更優,因為如果不在直徑上,它還會多出一小段距離.
然後就可以考慮在直徑上的話,顯然取直徑的中點(如果有的話)會最優,因為此時相當於平分直徑,然後使得可能的答案盡量小了.
如果沒有直徑中點的話,那麼我們可以找到一條「中邊」,使得其斷開的直徑兩端距離之差最小.
那麼我們找的策略也就出來了.直接找到兩棵子樹上直徑的 "中邊",然後對兩條中邊上的四個點進行討論選取即可.
#include#define ll long long
const ll inf=192608173;
using namespace std;
const int maxn=5008;
struct sj
a[maxn*2];
int head[maxn],size;
int v[maxn],now[maxn];
int road[maxn],road1[maxn];
int n,num,cntt,cnt,x,y,w;
ll nowdis,maxx,ans=inf;
ll xx[maxn],xx1[maxn],dis[maxn];
ll dis1,dis2,dis3,dis4;
int read()
while(ch<='9'&&ch>='0')
return f*w;
}void add(int x,int y,int w)
void dfs(int x)
}if(nowdis>maxx)
v[x]=0; num--;return;
}int main()
}//找到"中邊"
v[road1[i]]=1; maxx=-1;
//給左邊打上標記
dfs(road1[i+1]);
dfs(road[cnt]);
maxx2=maxx;
for(int j=1;jmaxx2-x2)
}v[road1[i]]=0;
ans=min(ans,max(dis1+dis3+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis1+dis4+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis2+dis3+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis2+dis4+xx1[i],max(maxx1,maxx2)));
}cout<}
TJOI2017 城市(樹的直徑)
從加里敦大學城市規劃專業畢業的小明來到了乙個地區城市規劃局工作。這個地區一共有ri座城市,1條高速公路,保證了任意兩運城市之間都可以通過高速公路相互可達,但是通過一條高速公路需要收取一定的交通費用。小明對這個地區深入研究後,覺得這個地區的交通費用太貴。小明想徹底改造這個地區,但是由於上司給他的資源有...
TJOI2017 城市 樹形dp
這是個神仙題,會卡常 題目讓你改一條邊把直徑變得最短。列舉每條邊,會把圖分成兩個地方,兩個連通塊 x區和y區域 都換根dp一下,算出離x最遠的點的距離記為dis x 然後列舉一下 新直徑有三個 1 max dis x x裡面最大的 2 dis y y裡面最大的 3 min dis x dis y l...
TJOI 2017 城市 題解
題目傳送門 題目大意 給一棵邊帶權的樹,你可以將一條邊換個位置,換完之後還得是一棵樹,要求換完之後樹的直徑最小。o n o n o n 做法太強了,只能想到 o n 2 o n 2 o n2 的做法 考慮列舉刪去哪一條邊,假如刪掉當前列舉的邊,那麼整棵樹會被分成兩個部分,然後我們要把這條邊重新找個位...