POJ 1848

题意:给定一棵树,要添加一些边,不能是重边,不能是自环,让它的每一个结点都恰好属于一个环,求最少添加的边数。

题解:树形dp:dp[now][0]为以now为根的子树完成题目要求添加的最少边。

        dp[now][1]为除开now这个结点后它的子树满足题目要求所需要的最少边。

        dp[now][2]为now和它的某一个孩子形成至少长度为2的链所需要添加的最少边,未涉及到的点均已满足题目要求。

   转移方程:dp[now][1]=sum(dp[k][0]),k为now的孩子。

        dp[now][2]=sum(dp[k][0])-dp[i][0]+min(dp[i][1],dp[i][2]),即从孩子中找一个,now会与它组成长度大于等于2的链

        dp[now][0]=sum(dp[k][0])-dp[i][0]+dp[i][2]+1或sum(dp[k][0])-dp[i][0]-dp[j][0]+min(dp[i][1],dp[i][2])+min(dp[j][1],dp[j][2]),前者是找一个有长度至少为2的链的孩子,后者是找两个没有形成环的孩子。

View Code
 1 #include<cstdio>

 2 #include<cstring>

 3 #include<algorithm>

 4 using namespace std;

 5 const int inf=1000,N=105;

 6 int dp[N][3],head[N],nc;

 7 bool vis[N];

 8 struct Edge

 9 {

10     int to,next;

11 } edge[N*4];

12 void add(int a,int b)

13 {

14     edge[nc].to=b;

15     edge[nc].next=head[a];

16     head[a]=nc++;

17     edge[nc].to=a;

18     edge[nc].next=head[b];

19     head[b]=nc++;

20 }

21 void dfs(int now)

22 {

23     vis[now]=true;

24     int t,stk[N],top=0,sumc=0,v;

25     dp[now][1]=0;

26     for(int i=head[now]; i!=-1; i=edge[i].next)

27     {

28         t=edge[i].to;

29         if(vis[t])

30             continue;

31         stk[top++]=t;

32         dfs(t);

33         sumc+=dp[t][0];

34     }

35     if(top==0)

36     {

37         dp[now][0]=dp[now][2]=inf;

38         dp[now][1]=0;

39         return;

40     }

41     dp[now][1]=sumc;

42     v=inf;

43     for(int i=0;i<top;i++)

44     {

45         t=stk[i];

46         v=min(v,sumc-dp[t][0]+min(dp[t][1],dp[t][2]));

47     }

48     dp[now][2]=v;

49     v=inf;

50     for(int i=0;i<top;i++)

51     {

52         int t1=stk[i];

53         v=min(sumc-dp[t1][0]+dp[t1][2]+1,v);

54         for(int j=i+1;j<top;j++)

55         {

56             int t2=stk[j];

57             v=min(sumc-dp[t1][0]-dp[t2][0]+min(dp[t2][1],dp[t2][2])+min(dp[t1][1],dp[t1][2])+1,v);

58         }

59     }

60     dp[now][0]=v;

61 }

62 int main()

63 {

64     int n;

65     while(scanf("%d",&n)!=EOF)

66     {

67         memset(head,-1,sizeof(head));

68         nc=0;

69         memset(vis,false,sizeof(vis));

70         for(int i=1,a,b;i<n;i++)

71         {

72             scanf("%d%d",&a,&b);

73             add(a,b);

74         }

75         dfs(1);

76         if(dp[1][0]<inf)

77             printf("%d\n",dp[1][0]);

78         else

79             printf("-1\n");

80     }

81     return 0;

82 }

你可能感兴趣的:(poj)