poj1947 Rebuilding Roads
题目大意:求树上隔离出k个点的最少删除的边数。n,k<=150 空间限制30000k
题解:
(看了网上的题解大雾了一天TAT)
(但是当你一旦弄明白后发现卧槽他们说的好对啊哭晕QAQ)
首先这样想 dp[i,j] 表示以i为根节点的子树剩余j个节点删除的最多的边数 这样 相当于分组背包(当时一直不明白QAQ蠢) dp[i,j]有son[i] 个分组,每次都从以i为根的物品组中选择一个物品进行转移,每组选择一个物品。
和01背包类似 分组背包也有二维和一维两组写法(这里是三维和二维)
三维MLE 二维正解……
UP:背包问题值得好好研究一番……
背包九讲
贴代码:三维MLE
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200;
const int inf=0x7fffffff;
struct E {int to,nxt;}edge[N*2];
int idx[N],tot=1,cnt[N];
int n,k,ans=inf,root;
int dp[N][N][N],son[N];
bool vis[N];
void addedge(int from,int to){
edge[tot].to=to;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void dfs(int x,int fa){
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
if(e.to!=fa){
dfs(e.to,x);
son[x]++;
}
}
if(x==root) fill(dp[x][1],dp[x][1]+1+son[x],son[x]);
else fill(dp[x][1],dp[x][1]+1+son[x],son[x]+1);
int Cnt=0;
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
if(e.to!=fa){
Cnt++;
for(int i=2;i<=k;i++){
dp[x][i][Cnt]=dp[x][i][Cnt-1];
for(int j=1;j<i;j++)
dp[x][i][Cnt]=min(dp[x][i][Cnt],dp[x][i-j][Cnt-1]+dp[e.to][j][son[e.to]]-2);
}
//if(x==4) printf("%d<",dp[x][4][Cnt]);
}
}
//printf("%d %d %d\n",x,5,dp[x][5][son[x]]);
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);cnt[y]++;
}
for(int i=0;i<N;i++)for(int j=0;j<N;j++)for(int k=0;k<N;k++)dp[i][j][k]=1000000;
for(int i=1;i<=n;i++) if(!cnt[i]) root=i,dfs(i,0);
int ans=dp[root][k][son[root]];
for(int i=1;i<=n;i++) if(i!=root) ans=min(ans,dp[i][k][son[i]]);
printf("%d\n",ans);
return 0;
}
二维正解
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200;
const int inf=0x7fffffff;
struct E {int to,nxt;}edge[N*2];
int idx[N],tot=1,cnt[N];
int n,k,ans=inf,root;
int dp[N][N],son[N];
bool vis[N];
void addedge(int from,int to){
edge[tot].to=to;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void dfs(int x,int fa){
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
if(e.to!=fa){
dfs(e.to,x);
son[x]++;
}
}
if(x==root) dp[x][1]=son[x];
else dp[x][1]=son[x]+1;
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
if(e.to!=fa){
for(int i=k;i>=2;i--){
for(int j=1;j<i;j++)
dp[x][i]=min(dp[x][i],dp[x][i-j]+dp[e.to][j]-2);
}
//if(x==4) printf("%d<",dp[x][4][Cnt]);
}
}
//printf("%d %d %d\n",x,5,dp[x][5][son[x]]);
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);cnt[y]++;
}
for(int i=0;i<N;i++)for(int j=0;j<N;j++)dp[i][j]=1000000;
for(int i=1;i<=n;i++) if(!cnt[i]) root=i,dfs(i,0);
int ans=dp[root][k];
for(int i=1;i<=n;i++) if(i!=root) ans=min(ans,dp[i][k]);
printf("%d\n",ans);
return 0;
}