POJ1848--Tree ——树形dp

题意:给你一个树,问你最少连几条边可以让树中的每一个节点在且只在一个环内。如果无法完成就输出-1。

我们设dp[i][0]为根节点为i的树变成每一个节点都在且只在一个环里所需要的最小边数。dp[i][1]为除了根节点i外其他点都在且只在一个环里所需要的最小边数。

dp[i][2]为除了根节点和一个子节点(以及子节点可有可无的链)都在且只在一个环里所需要的最小边数。

这样我们的状态转移需要考虑以下4种情况:

(第一张图最上面应该是dp[i][1]  当时写错了不好改)

 

 

  

具体代码如下:

#include<iostream>
#include<vector>
using namespace std;
#define ll long long
const ll inf=100000000;
ll dp[105][3];
vector<int> a[105];
void solve(int u,int f)
{
    int i,j;
    if(a[u].size()==1&&a[u][0]==f)
    {
        dp[u][0]=inf;
        dp[u][1]=0;
        dp[u][2]=inf;
        //
        return;
    }
    for(i=0;i<a[u].size();i++)
    {
        if(a[u][i]==f) continue;
        solve(a[u][i],u);
    }
    ll sum=0; 
    for(i=0;i<a[u].size();i++)
    {
        if(a[u][i]==f) continue;
        sum+=dp[a[u][i]][0];
    }
    dp[u][1]=min(dp[u][1],sum);
    for(i=0;i<a[u].size();i++)
    {
        if(a[u][i]==f) continue;
        ll now=sum-dp[a[u][i]][0]+min(dp[a[u][i]][1],dp[a[u][i]][2]);
        ll now1=sum-dp[a[u][i]][0]+dp[a[u][i]][2]+1;
        dp[u][2]=min(dp[u][2],now);
        dp[u][0]=min(dp[u][0],now1);
    }
    for(i=0;i<a[u].size()-1;i++)
    for(j=i+1;j<a[u].size();j++)
    {
        if(a[u][i]==f||a[u][j]==f) continue;
        ll now=1+sum-dp[a[u][i]][0]-dp[a[u][j]][0]+min(dp[a[u][i]][1],dp[a[u][i]][2])+min(dp[a[u][j]][1],dp[a[u][j]][2]);
        //cout<<u<<i<<j<<" "<<min(dp[a[u][i]][1],dp[a[u][i]][2])<<" "<<min(dp[a[u][j]][1],dp[a[u][j]][2])<<endl;
        dp[u][0]=min(dp[u][0],now);
    }
    
}

int main()
{
    int i,n,x,j,y;
    cin>>n;
    for(i=0;i<n-1;i++) 
    {
        cin>>x>>y;
        a[x].push_back(y);
        a[y].push_back(x);
    }
    for(i=1;i<=n;i++)
    for(j=0;j<=2;j++) dp[i][j]=inf;
    solve(1,-1);
    ll ans=inf;
    ans=dp[1][0];
    if(ans==inf) cout<<"-1"<<endl;
    else cout<<ans<<endl;
    //for(i=1;i<=n;i++) cout<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<endl;
}

 

posted @ 2019-04-20 17:34  啾啾猫猫  阅读(247)  评论(0编辑  收藏  举报