POJ_1947 Rebuilding Roads--ツリーDP
2656 ワード
http://poj.org/problem?id=1947
n個の点が1つの木を構成して、少なくともどれだけの辺を削除して1本のp個の結点の子の木を得ることができますか?
解析:ツリーDP.
構想:iをルートとするサブツリーにj個のノードが残っている場合に最も除去すべき辺数をdp[i][j]で表す.
ここでiノードのサブツリーは必ずしも2本しかないとは限らないので,各サブツリーの残りのノードの割り当てを直接列挙すると列挙に相当し,時間的複雑度が高すぎる.従って、DPにDPを1層装着し、iの前k本の木において、m個のノードが残っている場合の最小エッジ数をF[k][m]で表す必要がある.k本目の木のエッジを除去するか、除去しないかを考慮します.(1)、kサブツリーを除去する:F[k][m]=F[k-1][m]+1(+1の原因は、kサブツリーを一度除去するエッジを加えること)(2)、kサブツリーを除去しない:F[k][m]=min(F[k-1][m-m 1]+dp[root[k]][m 1]);(k子樹残m 1ノード)F[k][m]=min{F[k-1][m]+1,min{F[k-1][m-m 1]+dp[root[k]][m 1]};(上記の状態遷移を求めるときはスクロール配列で空間を最適化することができ、ここでは2次元REで、爆桟と推定され、ずっとRE).スクロール配列:F[m]=min{F[m]+1,min{F[m-m 1]+dp[root[k]][m 1]}} dp[i][j] = F[j]; 最終的な答えは、各ノードを最終ツリーのルートとして列挙し、最小値を導くことです.
n個の点が1つの木を構成して、少なくともどれだけの辺を削除して1本のp個の結点の子の木を得ることができますか?
解析:ツリーDP.
構想:iをルートとするサブツリーにj個のノードが残っている場合に最も除去すべき辺数をdp[i][j]で表す.
ここでiノードのサブツリーは必ずしも2本しかないとは限らないので,各サブツリーの残りのノードの割り当てを直接列挙すると列挙に相当し,時間的複雑度が高すぎる.従って、DPにDPを1層装着し、iの前k本の木において、m個のノードが残っている場合の最小エッジ数をF[k][m]で表す必要がある.k本目の木のエッジを除去するか、除去しないかを考慮します.(1)、kサブツリーを除去する:F[k][m]=F[k-1][m]+1(+1の原因は、kサブツリーを一度除去するエッジを加えること)(2)、kサブツリーを除去しない:F[k][m]=min(F[k-1][m-m 1]+dp[root[k]][m 1]);(k子樹残m 1ノード)F[k][m]=min{F[k-1][m]+1,min{F[k-1][m-m 1]+dp[root[k]][m 1]};(上記の状態遷移を求めるときはスクロール配列で空間を最適化することができ、ここでは2次元REで、爆桟と推定され、ずっとRE).スクロール配列:F[m]=min{F[m]+1,min{F[m-m 1]+dp[root[k]][m 1]}} dp[i][j] = F[j]; 最終的な答えは、各ノードを最終ツリーのルートとして列挙し、最小値を導くことです.
/*
Name: POJ_1947
Author:
Date: 27/09/11 14:03
Description: DP
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAX 160
#define INF 1000000
#define min(a,b) (a>b?b:a)
using namespace std;
int N,P,edge_num;
struct Node{
int num,next ;
}edge[MAX] ;
int g[MAX] ;
bool vis[MAX];
int dp[MAX][MAX];
void add(int a,int b)
{
++edge_num;
edge[edge_num].num = b ;
edge[edge_num].next = g[a] ;
g[a] = edge_num ;
}
void dfs(int node)
{
if(vis[node]) return ;
vis[node] = true ;
int i,j,son_num = 0,num,k,m,m1,min_;
//int F[MAX];
for(i=1;i<=N;i++)
{
dp[node][i] = INF ;
}
dp[node][0] = 0 ; // node 0
// 01 , DP DP
for(k=1,j=g[node];j!=-1;k++,j=edge[j].next)
{
num = edge[j].num ;
if(!vis[num])
dfs(num);
for(m=N;m>0;m--)
{
min_ = INF ;
if(k == 1)
{
//F[m] = dp[num][m] ;
dp[node][m] = dp[num][m-1]; // dp[node][m] F[m] ;
continue ;
}
else {
dp[node][m] = dp[node][m] + 1 ;
// F[m] = F[m] + 1;
}
for(m1=0;m1<m;m1++)
{
min_ = min(min_,dp[node][m-m1-1]+dp[num][m1]) ;
}
dp[node][m] = min(min_,dp[node][m]) ;
//F[m] = min(min_,F[m]);
}
dp[node][0]++ ;
}
/*
for(i=2;i<=N;i++)
{
dp[node][i] = F[i-1];
}
*/
}
int main()
{
//freopen("1in.txt","r",stdin);
//freopen("1out.txt","w",stdout);
int i,a,b,j;
while(scanf("%d %d",&N,&P)!=EOF)
{
edge_num = 0 ;
memset(vis,false,sizeof(vis));
memset(g,-1,sizeof(g));
for(i=1;i<N;i++)
{
scanf("%d %d",&a,&b);
add(a,b) ;
}
dfs(1);
int min_ = dp[1][P-1] ;
for(j=2;j<=N;j++) // 。
{
min_ = min(min_,dp[j][P-1]+1) ;
}
printf("%d
",min_);
//system("pause");
}
return 0;
}