Perfect Domination on Trees [UVALive 3346] 树形DP

题意:

给你一棵树,用黑白染色,求最少的染黑的个数,使得每个白点都与且只与1个黑点相连。

题解:

dp[x][f]表示将x染成f状态最少需要染多少黑点,f有三种状态:0,1,2

0:表示该点为白色,且他的所有儿子都为白色。

1:表示该点为黑色。

2:表示该点为白色,且他有一个儿子为黑色。

dp[x][1]=sigma(min(dp[son(x)][1],dp[son(x)][0]));

dp[x][0]=sigma(dp[son(x)][2]);

dp[x][2]=min(dp[son(xi)][1]+sigma(dp[son(!xi)][2]));//xi为枚举的某个染黑的儿子,!xi为剩下的儿子。

 

More:

开始题目看错了,看错每个白点至少和一个黑点相连,这样的话状态转移为:

 

dp[x][1]=sigma(min(dp[son(x)][1],dp[son(x)][0],dp[son(x)][2]));

dp[x][0]=sigma(dp[son(x)][2]);

dp[x][2]=min(dp[son(xi)][1]+sigma(min(dp[son(!xi)][2],dp[son(!xi)][2])));//xi为枚举的某个染黑的儿子,!xi为剩下的儿子。

 

代码:

 

#include <stdio.h>

#include <memory.h>

#include <iostream>

#include <algorithm>

#include <vector>

#include <map>

using namespace std;

#define N 1005

#define INF 100000

vector<int> tr[N],t[N];

int dp[N][4];

int father[N];

bool visited[N];

map<int ,int > mp;

void build_tree(int x)

{

int i;

visited[x]=1;

for(i=0;i<t[x].size();i++)

if (!visited[t[x][i]])

{

father[t[x][i]]=x;

build_tree(t[x][i]);

}

}

int min(int x,int y)

{

if (x<y) return x;

else return y;

}

int tree_dp(int x,int f)

{

if (dp[x][f]!=-1) return dp[x][f];

int i,j,sum;

if (f==1)

{

     sum=0;

 for(i=0;i<tr[x].size();i++)

    sum+= min( tree_dp(tr[x][i],1),tree_dp(tr[x][i],0) );

 dp[x][f]=sum+1;

}

if (f==0)

{

sum=0;

  for(j=0;j<tr[x].size();j++)

sum+=tree_dp(tr[x][j],2);

  dp[x][f]=sum;

}

if (f==2)

{

sum=0;

       int ans=INF;

         for(i=0;i<tr[x].size();i++)

{

            sum=tree_dp(tr[x][i],1);

for(j=0;j<tr[x].size();j++)

if (i!=j)

sum+=tree_dp(tr[x][j],2);

if (sum<ans) ans=sum;

}

dp[x][f]=ans;

}

return dp[x][f];

}

int main()

{

int n,i,j,x,y;

while(cin>>n)

    {

mp.clear();

int cnt=0;

if (n==0) break;

for(i=1;i<=n+1;i++)

t[i].clear();

for(i=1;i<=n;i++)

{

cin>>x>>y; 

if ( mp.find(x)==mp.end() ) mp[x]=++cnt;

if ( mp.find(y)==mp.end() ) mp[y]=++cnt;

x=mp[x];y=mp[y];

t[x].push_back(y);

t[y].push_back(x);

}

n++;

   father[1]=0;

memset(visited,0,sizeof(visited));

        build_tree(1); 

for(i=1;i<=n;i++)

{

tr[i].clear();

for(j=0;j<t[i].size();j++)

if (t[i][j]!=father[i])

tr[i].push_back(t[i][j]);

}

memset(dp,-1,sizeof(dp));

     int ans=min(

        tree_dp(1,2),

tree_dp(1,1));

 cout<<ans<<endl;

}

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值