一座城市,每每會被人們劃分爲幾個區域,例如住宅區、商業區、工業區等等。B市就被分爲了如下的兩個區域——城市中心和城市郊區。在着這兩個區域的中間是一條圍繞B市的環路,環路以內即是B市中心。ios
整個城市能夠看作一個N個點,N條邊的單圈圖(保證圖連通),惟一的環即是繞城的環路。保證環上任意兩點有且只有2條路徑互通。圖中的其它部分皆隸屬城市郊區。數組
如今,有一位名叫Jim的同窗想在B市開店,可是任意一條邊的2個點不能同時開店,每一個點都有必定的人流量Pi,在該點開店的利潤就等於該店的人流量Pi×K(K≤10000),K的值將給出。ide
Jim想盡可能多的賺取利潤,請問他應該在哪些地方開店?函數
第一行一個整數N 表明城市中點的個數。城市中的N個點由0~N-1編號。測試
第二行N個正整數,表示每一個點的人流量Pi(Pi≤10000)。ui
下面N行,每行2個整數A,B,表示A,B建有一條雙向路。spa
最後一行一個實數K。code
一個實數M,(保留1位小數),表明開店的最大利潤。orm
4 1 2 1 5 0 1 0 2 1 2 1 3 2
12.0
【數據範圍】blog
對於20%的數據,N≤100.
對於另外20%的數據,環上的點不超過2000個
對於50%的數據 N≤50000.
對於100%的數據 N≤100000.
基環樹
咱們都知道,出題人都以出出有意義的題目爲己任【其實就是毒瘤
當咱們能夠熟練掌握圖上和樹上的任務的時候,出題人不爽了。
某一天,某位毒瘤出題人在深夜被汽車吵醒,以後終於發現一個神奇的東西。
集樹形結構和環路於一體,又不至於不可作的東西。
基環樹!!!
【上面都是我本身yy的QAQ
無論過程到底是什麼樣子的了,總之,咱們如今有可能考這個奇怪的東西。
究竟什麼是基環樹呢?
私自定義1:
在一棵樹上面,加一條邊,造成一顆只含有一個環的樹【霧
好比這張圖。【對不起我又盜圖了QAQ
私自定義2:
一張只有一個環的圖。
既然能夠當作一張圖,咱們都知道圖是能夠有向的。
那麼基環樹也是能夠有向的。
指向環的:內向基環樹
起源於環的:外向基環樹。
那麼怎麼才能解決這種問題呢?一會在題面中解釋吧。
咱們從題面中有這樣一句話:
N條邊的單圈圖(保證圖連通),惟一的環即是繞城的環路。
這說明了什麼?
構想一下地圖的場景,假設只有一個環,那麼這張圖就是一顆基環樹。
啊啊啊,好但願這能是一顆樹啊?
這樣就能採起樹形DP了啊QAQ
emmm,好像是有辦法的,指變成樹。
咱們仔細想一想,這是一顆在樹上加了一條邊造成的結構。
若是想從新變成一顆樹,那麼直接刪邊不就行了嘛?
那麼究竟刪哪條邊才合適呢?
刪環上的邊是無疑的,畢竟要保證圖的的連通性。
可是,環上的邊有那麼多條,難道要所有都刪一遍嗎?
固然不可能啊?怎麼證實呢?
實際上,咱們考慮樹形DP自己的一些性質。
咱們定義 f [ i ] 數組來記錄以 i 爲根的子樹的性質。
而後,咱們能夠任意選擇一條邊,分別從這條邊的左右端點各跑一次樹形DP。
這樣咱們能夠獲得兩個數組,f [ ],f ' [ ]
可是因爲自己定義是重合的,因此,這個數組維護的信息就同時包括着:
1. 左節點選,右節點不選
2. 左節點不選,右節點選
3. 左右節點都不選
這三種狀況,恰好把不知足題意的「都選」操做給忽略了,正好是咱們所須要的。
那麼天然,跑兩遍tree DP就OK了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define ll long long 7 #define uint unsigned int 8 using namespace std; 9 10 const int MA=1e6+10; 11 ll n,val[MA]; 12 struct ss{ 13 ll to,nxt; 14 }tr[MA*2]; 15 ll head[MA],ecnt=1; 16 17 inline void add(ll a,ll b) { 18 tr[++ecnt].nxt=head[a]; 19 tr[ecnt].to=b; 20 21 head[a]=ecnt; 22 return; 23 } 24 25 ll sta,ed,bian; 26 27 28 bool vis[MA]; 29 30 void dfs(ll x,ll fa) { 31 vis[x]=1; 32 for(uint i=head[x];i;i=tr[i].nxt) { 33 ll y=tr[i].to; 34 if(y==fa) 35 continue; 36 if(vis[y]) { 37 sta=x; 38 ed=y; 39 bian=i; 40 41 42 continue; 43 } 44 dfs(y,x); 45 } 46 return; 47 } 48 49 double f[MA][2]; 50 51 void dp(ll x,ll fa) { 52 f[x][0]=0; 53 f[x][1]=val[x]; 54 for(uint i=head[x];i;i=tr[i].nxt) { 55 ll y=tr[i].to; 56 if(i==bian||i==(bian^1)) 57 58 continue; 59 if(y==fa) 60 continue; 61 dp(y,x); 62 f[x][0]+=max(f[y][0],f[y][1]); 63 f[x][1]+=f[y][0]; 64 } 65 return; 66 } 67 68 int main() 69 { 70 scanf("%lld",&n); 71 72 for(uint i=1;i<=n;i++) 73 scanf("%lld",&val[i]); 74 for(uint i=1;i<=n;i++) { 75 ll x,y; 76 scanf("%lld%lld",&y,&x); 77 78 x++,y++; 79 add(y,x); 80 81 add(x,y); 82 83 } 84 double k; 85 scanf("%lf",&k); 86 87 double ans=0; 88 dfs(1,1); 89 dp(sta,sta); 90 double tmp=f[sta][0]; 91 dp(ed,ed); 92 ans+=max(tmp,f[ed][0]); 93 printf("%.1lf\n",ans*k); 94 return 0; 95 }
Z國的騎士團是一個頗有勢力的組織,幫會中匯聚了來自各地的精英。他們劫富濟貧,懲惡揚善,受到社會各界的讚賞。
最近發生了一件可怕的事情,邪惡的Y國發動了一場針對Z國的侵略戰爭。戰火綿延五百里,在和平環境中安逸了數百年的Z國又怎能抵擋的住Y國的軍隊。因而人們把全部的但願都寄託在了騎士團的身上,就像期待有一個真龍天子的降生,帶領正義戰勝邪惡。
騎士團是確定具備戰勝邪惡勢力的能力的,可是騎士們互相之間每每有一些矛盾。每一個騎士都有且僅有一個本身最厭惡的騎士(固然不是他本身),他是絕對不會與本身最厭惡的人一同出征的。
戰火綿延,人民生靈塗炭,組織起一個騎士軍團加入戰鬥刻不容緩!國王交給了你一個艱鉅的任務,從全部的騎士中選出一個騎士軍團,使得軍團內沒有矛盾的兩人(不存在一個騎士與他最痛恨的人一同被選入騎士軍團的狀況),而且,使得這支騎士軍團最具備戰鬥力。
爲了描述戰鬥力,咱們將騎士按照1至N編號,給每名騎士一個戰鬥力的估計,一個軍團的戰鬥力爲全部騎士的戰鬥力總和。
輸入文件knight.in第一行包含一個正整數N,描述騎士團的人數。
接下來N行,每行兩個正整數,按順序描述每一名騎士的戰鬥力和他最痛恨的騎士。
輸出文件knight.out應包含一行,包含一個整數,表示你所選出的騎士軍團的戰鬥力。
3 10 2 20 3 30 1
30
對於30%的測試數據,知足N ≤ 10;
對於60%的測試數據,知足N ≤ 100;
對於80%的測試數據,知足N ≤ 10 000。
對於100%的測試數據,知足N ≤ 1 000 000,每名騎士的戰鬥力都是不大於 1 000 000的正整數
經過觀察題面,咱們發現,這張圖上面頗有可能不止一個環,甚至可能不是聯通的。
可是,能夠感性理解一下,對於每個聯通塊,有且僅有一個環。
爲何呢?
由於,每一個節點都要有一條出邊【我恨他,和不少條入邊【你們都恨我
那麼有資格向下發出一條出邊的節點也就是根節點了。
如此一來,這就是一片基環樹森林。
既然有了基環樹這麼一個優秀的性質,對於森林只須要保證所有的樹都被遍歷到就行了。
最後還有一點,本題的圖不是有向圖,恨的關係看起來是單向的,但本質上是雙向的。
好比說A恨B,而後B知道A恨他,因而也不想跟A一塊走。【由愛生恨?
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define ll long long 7 #define uint unsigned int 8 using namespace std; 9 10 const int MA=1e6+10; 11 ll n,val[MA]; 12 struct ss{ 13 ll to,nxt; 14 }tr[MA*2]; 15 ll head[MA],ecnt=1; 16 17 inline void add(ll a,ll b) { 18 tr[++ecnt].nxt=head[a]; 19 tr[ecnt].to=b; 20 21 head[a]=ecnt; 22 return; 23 } 24 25 ll sta,ed,bian; 26 27 bool vis[MA]; 28 29 void dfs(ll x,ll fa) { 30 vis[x]=1; 31 for(uint i=head[x];i;i=tr[i].nxt) { 32 ll y=tr[i].to; 33 if(y==fa) 34 continue; 35 if(vis[y]) { 36 sta=x; 37 ed=y; 38 bian=i; 39 40 continue; 41 } 42 dfs(y,x); 43 } 44 return; 45 } 46 47 ll f[MA][2]; 48 49 void dp(ll x,ll fa) { 50 f[x][0]=0; 51 f[x][1]=val[x]; 52 for(uint i=head[x];i;i=tr[i].nxt) { 53 ll y=tr[i].to; 54 if(i==bian||i==(bian^1)) 55 56 continue; 57 if(y==fa) 58 continue; 59 dp(y,x); 60 f[x][0]+=max(f[y][0],f[y][1]); 61 f[x][1]+=f[y][0]; 62 } 63 return; 64 } 65 66 int main() 67 { 68 scanf("%lld",&n); 69 70 for(uint i=1;i<=n;i++) { 71 ll x; 72 scanf("%lld%lld",&val[i],&x); 73 74 add(i,x); 75 76 add(x,i); 77 78 } 79 ll ans=0; 80 for(uint i=1;i<=n;i++) { 81 if(vis[i]) 82 continue; 83 dfs(i,i); 84 dp(sta,sta); 85 ll tmp=f[sta][0]; 86 dp(ed,ed); 87 ans+=max(tmp,f[ed][0]); 88 } 89 printf("%lld\n",ans); 90 return 0; 91 }
提交代碼以前必定要看好dfs函數,有沒有出現無線遞歸的狀況,否則會MLE。QAQ
祝你們AC愉快!