题意:求一颗无向树的最小点覆盖。

本来一看是最小点覆盖,直接一下敲了二分图求最小割,TLE。

树形DP,叫的这么玄乎,本来是线性DP是线上往前\后推,而树形DP就是在树上,由叶子结点状态向根状态推。

dp[u][1/0]:表示,结点u,1:选择,0,:不选。dp值是以改点为根(目前为止,dfs遍历顺序自然决定了树的层)的已经选择点数,自然开始时不知道,对每个点,初值dp[u][0]=0、

dp[u][1]=1,回溯的时候:

1:dp[u][1]+=min(dp[v][1],dp[v][0]);该节点选择了,那么子节点可选可不选。

2:dp[u][0]+=dp[v][1];该节点没有选择,则其子节点必需选择。

#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
using namespace std;
int n;
vector<vector<int> >v(100010);
int vis[100010];
int dp[100010][2];
inline int minn(int a,int b)
{
if(a<b)return a;
return b;
}
void dfs(int u)
{
dp[u][0]=0; //不放,0个
dp[u][1]=1; //放一个,
for(int i=0;i<v[u].size();i++)
{
int vv=v[u][i];
if(!vis[vv])
{
vis[vv]=1;
dfs(vv);
dp[u][0]+=dp[vv][1]; //回溯时加上
dp[u][1]+=minn(dp[vv][1],dp[vv][0]);
}
}
}
int main()
{
scanf("%d",&n);
int tx,ty;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&tx,&ty);
v[tx].push_back(ty);
v[ty].push_back(tx);
}
vis[1]=1;
dfs(1);
cout<<minn(dp[1][0],dp[1][1]); //结果为根放与不放的状态最小值
return 0;
}

666,求最优时候方案数,

多一个DP方程即可。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n;
vector<vector<int> >v(100020);
int vis[100020];
struct state
{
int light;
int count;
};
state dp[100020][2];
inline int minn(int a,int b)
{
if(a<b)return a;
return b;
}
void dfs(int u)
{
dp[u][0].light=0; //不放,0个
dp[u][1].light=1; //放一个,
dp[u][0].count=dp[u][1].count=1;
for(int i=0;i<v[u].size();i++)
{
int vv=v[u][i];
if(!vis[vv])
{
vis[vv]=1;
dfs(vv);
dp[u][0].light+=dp[vv][1].light; //回溯时加上
dp[u][1].light+=minn(dp[vv][1].light,dp[vv][0].light); dp[u][0].count= dp[u][0].count*dp[vv][1].count%10007; if(dp[vv][1].light<dp[vv][0].light)
dp[u][1].count=dp[u][1].count*dp[vv][1].count%10007; else if (dp[vv][1].light>dp[vv][0].light)
dp[u][1].count=dp[u][1].count*dp[vv][0].count%10007; else
dp[u][1].count=dp[u][1].count*(dp[vv][0].count+dp[vv][1].count)%10007; }
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int tx,ty;
for(int i=0;i<=n;i++)
{
v[i].clear();vis[i]=0;
}
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&tx,&ty);
v[tx].push_back(ty);
v[ty].push_back(tx);
}
vis[1]=1;
dfs(1);
int ans1=minn(dp[1][0].light,dp[1][1].light); //结果为根放与不放的状态最小值
if(dp[1][0].light<dp[1][1].light)
{
printf("%d %d\n",ans1,dp[1][0].count);
}
else if(dp[1][0].light>dp[1][1].light)
{
printf("%d %d\n",ans1,dp[1][1].count);
}
else
{
int ans2= (dp[1][0].count%10007+dp[1][1].count%10007)%10007;
printf("%d %d\n",ans1,ans2);
}
}
return 0;
}

最新文章

  1. scheduleInRunLoop作用
  2. SQL注入判断方法总结(持续更新)
  3. asp检测数字类型函数
  4. archlinux安装图形界面
  5. ADB工具 获取ROOT权限及复制文件方法
  6. PHP 路径或URL操作
  7. UVA 315 315 - Network(求割点个数)
  8. html_entity_decode() 函数
  9. A*算法(八数码问题)
  10. log4cpp日志不能是溶液子体积
  11. Java反射机制浅析
  12. @Scheduled(cron = &quot;0 0 * * * ?&quot;)实现定时任务
  13. [51nod1206]Picture
  14. 数据规范化——sklearn.preprocessing
  15. gogs windows
  16. Struts 2 初步入门(一)
  17. jquery trigger函数和triggerHandler函数的对照
  18. ab压测札记(Apache Bench)
  19. centos7.3安装zip,unzip
  20. 【刷题】BZOJ 3551 [ONTAK2010]Peaks加强版

热门文章

  1. 爬虫4_python2
  2. Java的jdbc调用SQL Server存储过程Bug201906131119
  3. 国庆集训 || Wannafly Day4
  4. PAT (Basic Level) Practise (中文)-1031. 查验身份证(15)
  5. bootstrap历练实例: 垂直胶囊式的导航菜单
  6. NoSQL 之 Morphia 操作 MongoDB
  7. mysql中常用函数简介(不定时更新)
  8. linux运维中常用的指令
  9. 四:SQL语句介绍
  10. redux form