[luogu]P1272 重建道路[樹形DP]
阿新 • • 發佈:2017-10-29
一行 p12 有時 容易 時間 ont pri 農夫 san
[luogu]P1272
重建道路
——!x^n+y^n=z^n
題目描述
一場可怕的地震後,人們用N個牲口棚(1≤N≤150,編號1..N)重建了農夫John的牧場。由於人們沒有時間建設多余的道路,所以現在從一個牲口棚到另一個牲口棚的道路是惟一的。因此,牧場運輸系統可以被構建成一棵樹。John想要知道另一次地震會造成多嚴重的破壞。有些道路一旦被毀壞,就會使一棵含有P(1≤P≤N)個牲口棚的子樹和剩余的牲口棚分離,John想知道這些道路的最小數目。
輸入輸出格式
輸入格式:
第1行:2個整數,N和P
第2..N行:每行2個整數I和J,表示節點I是節點J的父節點。
輸出格式:
單獨一行,包含一旦被破壞將分離出恰含P個節點的子樹的道路的最小數目。
輸入輸出樣例
輸入樣例1#:
11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11
輸出樣例1#:
2
說明
【樣例解釋】
如果道路1-4和1-5被破壞,含有節點(1,2,3,6,7,8)的子樹將被分離出來
很容易想到樹形背包,用f[i][j]表示以i為根,刪得只剩下j個點的最少刪除。
f[i][j]=Min{f[v][k]+f[i][j-k]-2}(v為i的孩子)[(v,i)應該留下,可兩個決策都減了,要-2]。
初始化:f[i][1]=邊數,f[root][1]=邊數-1。
一開始理解錯題意,以為root一定要保留,結果就gg了,呵呵。
代碼:
1 //2017.10.29 2 //DP 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 using namespace std; 7 inline int read(); 8 int Min(int x,int y){return x<y?x:y;} 9 namespace lys{ 10 const int N = 150 + 7 ; 11 structedge{ 12 int to; 13 int next; 14 }e[N*3]; 15 int dp[N][N],pre[N],count[N],fa[N]; 16 int n,p,cnt,ans; 17 void add(int x,int y){e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;} 18 void dfs(int node){ 19 int i,j,k,v; 20 dp[node][1]=count[node]+(fa[node]!=0); 21 for(i=pre[node];~i;i=e[i].next){ 22 v=e[i].to; 23 dfs(v); 24 for(j=p;j>=2;j--) 25 for(k=1;k<j;k++) 26 dp[node][j]=Min(dp[node][j],dp[v][k]+dp[node][j-k]-2); 27 } 28 ans=Min(dp[node][p],ans); 29 } 30 int main(){ 31 int i,u,v; 32 n=read(); p=read(); 33 memset(pre,-1,sizeof pre); 34 memset(dp,0x7,sizeof dp); 35 ans=dp[1][1]; 36 for(i=1;i<n;i++){ 37 u=read(); v=read(); 38 add(u,v); 39 count[u]++; 40 fa[v]=u; 41 } 42 for(i=1;i<=n;i++) if(!fa[i]){dfs(i);break;} 43 printf("%d\n",ans); 44 return 0; 45 } 46 } 47 int main(){ 48 lys::main(); 49 return 0; 50 } 51 inline int read(){ 52 int kk=0,ff=1; 53 char c=getchar(); 54 while(c<‘0‘||c>‘9‘){ 55 if(c==‘-‘) ff=-1; 56 c=getchar(); 57 } 58 while(c>=‘0‘&&c<=‘9‘) kk=kk*10+c-‘0‘,c=getchar(); 59 return kk*ff; 60 }
[luogu]P1272 重建道路[樹形DP]