重建道路

問題 M(1288): 【基礎算法】重建道路

時間限制: 1 Sec  內存限制: 64 MB
提交: 93  解決: 42
[提交][狀態][我的提交]

題目描述

一場可怕的地震後,人們用N個牲口棚(1≤N≤150,編號1..N)重建了Farmer John的牧場。由於人們沒有時間建設多餘的道路,所以現在從一個牲口棚到另一個牲口棚的道路是惟一的。因此,牧場運輸系統可以被構建成一棵樹。
John想要知道另一次地震會造成多嚴重的破壞。有些道路一旦被毀壞,就會使一棵含有P(1≤P≤N)個牲口棚的子樹和剩餘的牲口棚分離,John想知道這些道路的最小數目。
例如,如圖所示的牧場,要求P=6。如果道路1-4和1-5被破壞,含有節點(1,2,3,6,7,8)的子樹將被分離出來。

輸入

第1行:2個整數,N和P 
第2..N行:每行2個整數I和J,表示節點I是節點J的父節點。

輸出

第1行:1個整數,表示一旦被破壞將分離出恰含P個節點的子樹的道路的最小數目。

樣例輸入

 (如果複製到控制檯無換行,可以先粘貼到文本編輯器,再複製)

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

樣例輸出

2
分析:多叉樹轉二叉樹,分配,剛開始做題時沒有看見是分出一棵子樹,還以爲分出p個點就可以了,然後WA了很久(TAT),後來發現了,又懶得改了吧p和n-p都做一次dfs,再特判是否爲樹。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int N=150+10;
const int inf=0x7f7f7f7f;
void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
struct bian{
    int v,next;
}arr[N<<1];
struct node{
    int l,r;
}tree[N<<1];
int n,p,a,b,cnt,root,Ans;
int fir[N],way[N],son[N],dp[N][N];
bool fa[N],vis[N][N];
void link(int a,int b){
    arr[++cnt].v=a,arr[cnt].next=fir[b],fir[b]=cnt;
}
void Son(int x){
    if(!x)    return ;
    Son(tree[x].l),Son(tree[x].r);
    son[x]=son[tree[x].l]+son[tree[x].r]+1;
}
void dfs(int x,int k){
    if(vis[x][k])    return ;
    vis[x][k]=1;
    int tmp=inf;
    if(!k){dp[x][k]=0;return ;}
	if(k==son[tree[x].l]+1)	tmp=min(tmp,1);
    if(!tree[x].l&&!tree[x].r);
    else if(!tree[x].l){
        if(son[tree[x].r]>=k){
            dfs(tree[x].r,k);
            tmp=min(tmp,dp[tree[x].r][k]);
        }
        if(son[tree[x].r]>=k-1){
            dfs(tree[x].r,k-1);
            tmp=min(tmp,dp[tree[x].r][k-1]+way[x]);
        }
    }
    else if(!tree[x].r){
        if(son[tree[x].l]>=k){
            dfs(tree[x].l,k);
            tmp=min(tmp,dp[tree[x].l][k]);
        }
	}
    else{
		if(son[tree[x].r]>=k-son[tree[x].l]-1&&k-son[tree[x].l]-1>=0){
			dfs(tree[x].r,k-son[tree[x].l]-1);
			tmp=min(tmp,dp[tree[x].r][k-son[tree[x].l]-1]+1);
		}
        for(int i=0;i<=k;i++){
            if(son[tree[x].l]<i||son[tree[x].r]<k-i)    continue ;
            dfs(tree[x].l,i);
            dfs(tree[x].r,k-i);
            tmp=min(tmp,dp[tree[x].l][i]+dp[tree[x].r][k-i]);
        }
    }
    dp[x][k]=tmp;
}
int main(){
    getint(n),getint(p);
	if(p==n){
		printf("0\n");return 0;
	}
	if(p==1){
		printf("1\n");return 0;
	}
    for(int i=1;i<n;i++){
        getint(a),getint(b);
        link(b,a),fa[b]=1;
        way[a]++,way[b]++;
    }
    for(int i=1;i<=n;i++)if(!fa[i]){
        root=i;break ;
    }
    for(int i=1;i<=n;i++){
        tree[i].l=arr[fir[i]].v;
        int now=tree[i].l;
        for(int j=arr[fir[i]].next;j;j=arr[j].next)
            tree[now].r=arr[j].v,now=arr[j].v;
    }
    Son(root),dfs(root,n-p),dfs(root,p);
	if(dp[root][p]<2||dp[root][n-p]<2)
		printf("%d\n",min(dp[root][n-p],dp[root][p]));
	else	printf("%d\n",dp[root][n-p]);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章