[ZJOI2007]時態同步(dfs+貪心)
阿新 • • 發佈:2018-09-24
ostream 同時 一個 != n) htm code zjoi2007 zjoi
小Q在電子工藝實習課上學習焊接電路板。一塊電路板由若幹個元件組成,我們不妨稱之為節點,並將其用數字1,2,3.進行標號。電路板的各個節點由若幹不相交的導線相連接,且對於電路板的任何兩個節點,都存在且僅存在一條通路(通路指連接兩個元件的導線序列)。
在電路板上存在一個特殊的元件稱為“激發器”。當激發器工作後,產生一個激勵電流,通過導線傳向每一個它所連接的節點。而中間節點接收到激勵電流後,得到信息,並將該激勵電流傳向與它連接並且尚未接收到激勵電流的節點。最終,激烈電流將到達一些“終止節點”――接收激勵電流之後不再轉發的節點。
激勵電流在導線上的傳播是需要花費時間的,對於每條邊e,激勵電流通過它需要的時間為t?,而節點接收到激勵電流後的轉發可以認為是在瞬間完成的。現在這塊電路板要求每一個“終止節點”同時得到激勵電路――即保持時態同步。由於當前的構造並不符合時態同步的要求,故需要通過改變連接線的構造。目前小QQ有一個道具,使用一次該道具,可以使得激勵電流通過某條連接導線的時間增加一個單位。請問小Q最少使用多少次道具才可使得所有的“終止節點”時態同步?
Solution
這題可以直接一遍dfs做,
我們對於一個節點,先遍歷它的所有子樹,從中貪心的找出到達葉子的最遠距離,並把這個作為局部最優解。
然後我們把其他所有子樹全部調整為那樣的距離,再向上回溯。
Code
#include<iostream> #include<cstdio> using namespace std; int head[500009],tot,n,s,x,y; long long z,ans; struct efe { int n,to; long long l; }an[1000009]; void add(int u,int v,long longl) { an[++tot].n=head[u]; an[tot].to=v; an[tot].l=l; head[u]=tot; } long long dfs(int u,int fa) { long long ma=0; for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)an[i].l+=dfs(an[i].to,u); for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)ma=max(ma,an[i].l);for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)ans+=ma-an[i].l; return ma; } int main() { cin>>n>>s; for(int i=1;i<n;++i) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); dfs(s,0); cout<<ans; return 0; }
[ZJOI2007]時態同步(dfs+貪心)