1. 程式人生 > >P1272 重建道路(樹形dp)

P1272 重建道路(樹形dp)

esp 輸入輸出格式 嚴重 span 地震 std 描述 event i++

P1272 重建道路

題目描述

一場可怕的地震後,人們用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)的子樹將被分離出來

技術分享
#include<iostream>
#include<cstdio>
#include<cstring>

#define N 151

using namespace std;
int n,m,ans,cnt,flag,w;
int head[N],son[N],vis[N]; struct node { int u,v,next; }e[N<<1]; inline int read() { int x=0,f=1;char c=getchar(); while(c>9||c<0){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } inline void add(int
u,int v) { e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt; } void dfs2(int u,int tot) { if(son[u]==m) { w=tot; return; } for(int i=head[u];i;i=e[i].next) { int v=e[i].v;if(vis[i])continue; if(son[u]-son[v]>=m) { vis[i]=1; son[u]-=son[v]; tot=tot+1; dfs2(u+1-1,tot); vis[i]=0; } } } void dfs(int u) { if(flag) return; for(int i=head[u];i;i=e[i].next) { dfs(e[i].v); if(son[u]<m) continue; else if(son[u]==m) { printf("1\n"); flag=1;return; } else { int tmp=son[u]; dfs2(u,0); ans=min(ans,w); son[u]=tmp; } } if(flag) return; } void dfs1(int u) { son[u]=1; for(int i=head[u];i;i=e[i].next) { dfs1(e[i].v); son[u]+=son[e[i].v]; } } int main() { int x,y; n=read();m=read(); if(m==1) { printf("1\n"); return 0; } for(int i=1;i<n;i++) { x=read();y=read(); add(x,y); } ans=0x3f3f3f3f;dfs1(1); dfs(1); if(!flag) printf("%d\n",ans); return 0; }
42分錯誤暴力

/*
顯然樹形dp
dp[i][j]:i為根斷掉子樹大小為j最小邊數
初始化dp[u][1]=1的度數
轉移時枚舉當前點斷掉多少,算出連到的兒子斷掉多少
因為由兒子轉移過來,他們之間的連邊不能斷
但是轉移時斷掉了兩次,所以答案減2 
*/

#include<iostream>
#include<cstdio>
#include<cstring>

#define N 151
#define inf 0x7f7f7f7f

using namespace std;
int dp[N][N],head[N],d[N];
int n,m,ans,cnt;
struct node
{
    int u,v,next; 
}e[N<<1];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>9||c<0){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

inline void add(int u,int v)
{
    e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;
}

void dfs(int u,int fa)
{
    dp[u][1]=d[u];
    for(int i=head[u];i;i=e[i].next)
    {
        if(e[i].v!=fa)
        {
            dfs(e[i].v,u);
            for(int j=m;j>=1;j--)
              for(int k=1;k<=j;k++)
                dp[u][j]=min(dp[u][j],dp[e[i].v][k]+dp[u][j-k]-2);
        }
    }ans=min(ans,dp[u][m]);
}

int main()
{
    int x,y;
    memset(dp,1,sizeof dp);
    n=read();m=read();
    for(int i=1;i<n;i++)
    {
        x=read();y=read();
        add(x,y);add(y,x);
        d[x]++;d[y]++;
    }
    ans=inf;
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}

P1272 重建道路(樹形dp)