Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
树型DP+背包用了三维DP。 DP[s][m][p]表示对结点s和s的前m棵子树切割成一颗结点数为p且以s为根的子树所需的最少切割数。 则根据第m棵子树是否被切割得到状态转移方程: dp[s][m][p]=min{dp[s][m-1][p]+1,min{dp[s][m-1][p-k]+dp[son(s,m)][all(s,m)][k]}} 其中all(s,m)表示s的第m棵子结点所含儿子的个数。 自底向上求解的时候,用一个队列存储当前儿子结点个数为0的结点,每从队列中取出一个结点,则将该结点的父节点儿子数减1。这样就避免了记忆化DP所消耗的递归空间。 废话不说,贴AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; int dp[151][151][151],fa[151],sonnum[151],sn[151]; queue<int> qs; vector<int> link[151]; int main(){ //freopen("in.txt","r",stdin); int N,P,i,j,k,f,s,si,tmp,r; while(scanf("%d %d",&N,&P)!=EOF){ memset(dp,0xff,sizeof(dp)); memset(fa,0,sizeof(fa)); memset(sonnum,0,sizeof(sonnum)); while(!qs.empty())qs.pop(); for(i=1;i<=N;i++)link[i].clear(); for(i=1;i<N;i++){ scanf("%d %d",&f,&s); link[f].push_back(s); sonnum[f]++; fa[s]=f; } for(i=1;i<=N;i++){ if(sonnum[i]==0)qs.push(i); sn[i]=sonnum[i]; } while(!qs.empty()){ s=qs.front();qs.pop(); r=s; if((--sonnum[fa[s]])==0)qs.push(fa[s]); dp[s][0][1]=0; for(i=1;i<=sn[s];i++){ si=link[s][i-1]; for(j=1;j<=P;j++){ if(dp[s][i-1][j]!=-1)dp[s][i][j]=dp[s][i-1][j]+1; else dp[s][i][j]=-1; for(k=1;k<j;k++){ if(dp[s][i-1][j-k]!=-1 && dp[si][sn[si]][k]!=-1){ tmp=dp[s][i-1][j-k] + dp[si][sn[si]][k]; if(dp[s][i][j]==-1 || dp[s][i][j]>tmp)dp[s][i][j]=tmp; } } } } } for(tmp=dp[r][sn[r]][P],i=1;i<=N;i++){ if(dp[i][sn[i]][P]!=-1 && tmp>(dp[i][sn[i]][P]+1))tmp=dp[i][sn[i]][P]+1; } printf("%d\n",tmp); } return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator