树形dp(树的染色问题)

There is a tree with NN vertices, numbered 1,2,,N1,2,…,N. For each ii (1iN11≤i≤N−1), the ii-th edge connects Vertex xixi and yiyi.

Taro has decided to paint each vertex in white or black. Here, it is not allowed to paint two adjacent vertices both in black.

Find the number of ways in which the vertices can be painted, modulo 109+7109+7.

Constraints

 

  • All values in input are integers.
  • 1N1051≤N≤105
  • 1xi,yiN1≤xi,yi≤N
  • The given graph is a tree.

Input

 

Input is given from Standard Input in the following format:

NN
x1x1 y1y1
x2x2 y2y2
::
xN1xN−1 yN1yN−1

Output

 

Print the number of ways in which the vertices can be painted, modulo 109+7109+7.

Sample Input 1

 

3
1 2
2 3

Sample Output 1

 

5

There are five ways to paint the vertices, as follows:

Sample Input 2

 

4
1 2
1 3
1 4

Sample Output 2

 

9

There are nine ways to paint the vertices, as follows:

Sample Input 3

 

1

Sample Output 3

 

2

Sample Input 4

 

10
8 5
10 8
6 5
1 5
4 8
2 10
3 6
9 2
1 7

Sample Output 4

 

157

题意:

给一棵树,用黑白两色给节点染色,其中两个相邻节点不能同为黑色,求染色的所有方法。

解题思路:

树形dp,建一个二维数组dpdp[i][j]为第i个点为jj=0,1即黑白)所有情况,然后找递推式,以1为根节点dfs即可。

代码:

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e6+100;
struct node{
    int to;
    int ne;
}e[maxn];
int head[maxn];
ll f[maxn][3]; 
int cnt=0;
void add(int u,int v){
    e[cnt].to=v;
    e[cnt].ne=head[u];
    head[u]=cnt++;
} 
void dfs(int u,int fa){
    f[u][1]=1;
    f[u][0]=1; 
    for(int i=head[u];~i;i=e[i].ne){
        int v=e[i].to;
        if(fa==v){
            continue;
        }
        dfs(v,u);
        ll sum1=(f[v][1]+f[v][0])%mod;
        ll sum2=(f[v][0])%mod; 
        f[u][1]=(f[u][1]*sum2)%mod;
        f[u][0]=(f[u][0]*sum1)%mod;
    }
}
int main(){
    memset(head,-1,sizeof(head));
    int n;
    cin>>n;
    int x,y;
    for(int i=1;i<=n-1;i++){
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    dfs(1,-1);
    cout<<(f[1][1]+f[1][0])%mod<<endl; 
} 

这个题和那个

P1352 没有上司的舞会

是不一样的

某大学有 nn 个职员,编号为 1ldots n1n。

他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r_iri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。

所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

输入格式

输入的第一行是一个整数 nn。

第 22 到第 (n + 1)(n+1) 行,每行一个整数,第 (i+1)(i+1) 行的整数表示 ii 号职员的快乐指数 r_iri

第 (n + 2)(n+2) 到第 2n2n 行,每行输入一对整数 l, kl,k,代表 kk 是 ll 的直接上司。

输出格式

输出一行一个整数代表最大的快乐指数。

输入输出样例

输入 #1
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出 #1
5

说明/提示

数据规模与约定

对于 100\%100% 的数据,保证 1leq n leq 6 imes 10^31n6×103,-128 leq r_ileq 127128ri127,1 leq l, k leq n1l,kn,且给出的关系一定是一棵树。

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
int n,s;
const int maxn=1e6+100;
struct node{
    int next;
    int e;
}e[maxn];
int a[maxn];
int head[maxn];
int cnt;
void add(int u,int v){
    e[cnt].e=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
int f[maxn][2];
void dfs(int u,int fa){
    f[u][1]=a[u];
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].e;
        if(fa==v){
            continue;
        }
        dfs(v,u);
        f[u][1]+=f[v][0];
        f[u][0]+=max(f[v][1],f[v][0]);
    }
}
int main(){
    memset(head,-1,sizeof(head));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n-1;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    } 
    dfs(1,-1);
    cout<<max(f[1][1],f[1][0])<<endl;
}

传送门

Bob 喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。

他要建立一个古城堡,城堡中的路形成一棵无根树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路。
注意:某个士兵在一个结点上时,与该结点相连的所有边将都可以被瞭望到。

 

输入

第一行两个整数n,表示树中结点的数目;
之后n-1行,每行两个数u,v,表示结点u,v之间有一条无向边;
结点标号在0到n-1之间,保证在输入数据中每条边只出现一次。

输出

输出仅包含一个整数,为所求的最少的士兵数目。

数据范围

对于100%的数据,1≤n≤100000。

输入样例

4
0 1
1 2
1 3

输出样例

1

样例解释

对于样例中的树,派一名士兵到结点1,即可瞭望到所有路。

这个题和上一个基本上一样

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100; 
struct node{
    int to;
    int ne;
}e[maxn];
int head[maxn];
int cnt=0;
int dp[maxn][2];
void add(int u,int v){
    e[cnt].to=v;
    e[cnt].ne=head[u];
    head[u]=cnt++;
}
void dfs(int u,int fa){
    dp[u][1]++;//放上 
    for(int i=head[u];~i;i=e[i].ne){
        int v=e[i].to;
        if(v==fa){
            continue;
        }
        dfs(v,u);
        dp[u][0]+=dp[v][1];
        dp[u][1]+=min(dp[v][0],dp[v][1]);
    }
}
int main(){
    int n;
    memset(head,-1,sizeof(head));
    cin>>n;
    int x,y;
    for(int i=1;i<=n-1;i++){
        cin>>x>>y;
        x++;
        y++;
        add(x,y);
        add(y,x);
    }    
    dfs(1,-1);
    cout<<min(dp[1][0],dp[1][1])<<endl; 
}
原文地址:https://www.cnblogs.com/lipu123/p/14509120.html