基本樹形dp及例題

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#define N 6005                            //樹形dp POJ2342
using namespace std;
struct tree
{
	int child, father, brother;                      //結點的子節點,父親結點, 兄弟結點
	int present, non_present;                       //present表示此人到場的最大價值, non_present表示此人不到場的最大價值
	void init()
	{
		child=father=brother=non_present=0;                //初始化
	}
}p[N];
void dfs(int x)
{
	int k=p[x].child;
	while(k)
	{
		dfs(k);      //深搜下去到子節點,從下到上
		p[x].present+=p[k].non_present;     //狀態轉移方程,x到場的話則加上它的孩子不到場的價值
		p[x].non_present+=max(p[k].present, p[k].non_present);//x不到場的話則加上他的孩子(到場或不到場---孩子和brother之間也不受影響)的最大值
		k=p[k].brother;     //x的孩子還包括(x的孩子的brother)
	}
	return ;
}
int main()
{
	int n, t, l, k;
	while(scanf("%d", &n)!=EOF)
	{
		for(t=1; t<=n; ++t)
		{
			scanf("%d", &p[t].present);
			p[t].init();
		}
		while(scanf("%d%d", &l, &k)!=EOF&&l+k!=0)
		{
			p[l].father=k;
			p[l].brother=p[k].child;   //一個接一個,記錄上一個
			p[k].child=l;     //可以從這裏逐漸往上推,推出k所有的child
		}
		for(t=1; t<=n; ++t)
		{
			if(!p[t].father)   //從根節點出發
			{
				dfs(t);     //搜索並記錄下來
				printf("%d\n", max(p[t].present, p[t].non_present));
				break;
			}
		}
	}
	return 0;
}






#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long 
#define inf 0x7fffffff
#define N 250
using namespace std;    //hdu2412  樹形dp及最佳方案是否唯一
int dp[N][2], dup[N][2];     //dp[n][m]中m爲0表示不來,m爲1表示來, dup[n][m]表示最佳的方案是不是唯一的,dup[n][m]中m爲0表示不唯一,m爲1表示唯一
map<string, int> s;
/*
題意:n個人形成一個關係樹,每個節點代表一個人,節點的根表示這個人的唯一的直接上司,只有根沒有上司。
要求選取一部分人出來,使得每2個人之間不能有直接的上下級的關係,求最多能選多少個人出來,並且求出獲得最大人數的選人方案是否唯一。
思路:樹形dp
     dp[x][0]+=max(dp[k][0], dp[k][1]);   k是x的孩子
	 dp[x][1]+=dp[k][0];
*/
struct node
{
	int pre, brother, son;
	void init()
	{
		pre=brother=son=0;
		return ;
	}
}p[N];

void dfs(int x)
{
	int k=p[x].son;
	dup[x][0]=dup[x][1]=1;  //注意初始化每個人來和不來都是唯一的方案
	while(k)
	{
		dfs(k);
		dp[x][0]+=max(dp[k][0], dp[k][1]);
		dp[x][1]+=dp[k][0];
		if((dp[k][0]>dp[k][1]&&!dup[k][0])||(dp[k][0]<dp[k][1]&&!dup[k][1])||dp[k][0]==dp[k][1])
			dup[x][0]=0;
		if(!dup[k][0])
			dup[x][1]=0;
		k=p[k].brother;
	}
	return ;
}

int main()
{
	int n, t, j, k, id1, id2;
	string s1, s2;
	while(scanf("%d", &n)&&n)
	{
		s.clear();
		memset(dp, 0, sizeof(dp));
		for(t=1; t<=n; ++t)
		{
			p[t].init();
			dp[t][1]=1;
		}
		k=1;
		cin>>s1;
		s[s1]=k++;
		for(t=1; t<n; ++t)
		{
			cin>>s1>>s2;
			if(!s[s1])
			{
				s[s1]=k++;
			}
			if(!s[s2])
			{
				s[s2]=k++;
			}
			id1=s[s1];
			id2=s[s2];
			p[id1].pre=id2;
			p[id1].brother=p[id2].son;
			p[id2].son=id1;
		}
		dfs(1);
		int ans, flag=0;
		if(dp[1][0]>dp[1][1])
		{
			ans=dp[1][0];
			if(dup[1][0]==1)
				flag=1;
		}
		else if(dp[1][0]<dp[1][1])
		{
			ans=dp[1][1];
			if(dup[1][1]==1)
				flag=1;
		}
		else 
		{
			ans=dp[1][0];
		}
		printf("%d ", ans);
		if(flag)
		{
			printf("Yes\n");
		}
		else printf("No\n");
	}
	return 0;
}











#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long 
#define inf 0x7fffffff
#define N 2500
using namespace std;     //hdu1054   樹形dp
int dp[N][2];   
struct node
{
    int pre, brother, son;
    void init()
    {
        pre=brother=son=0;
        return ;
    }
}p[N];

void dfs(int x)
{
    int k=p[x].son;
    while(k)
    {
        dfs(k);
        dp[x][0]+=dp[k][1];
        dp[x][1]+=min(dp[k][0], dp[k][1]);
        k=p[k].brother;
    }
    return ;
}

int main()
{
    int n, t, a, k, b;
    while(scanf("%d", &n)!=EOF)
    {
        memset(dp, 0, sizeof(dp));
        for(t=1; t<=n; ++t)
        {
            p[t].init();
            dp[t][1]=1;
        }
        for(t=0; t<n; ++t)
        {
            scanf("%d:(%d)", &a, &k);   //注意這裏編號可以從0開始,所以每一個編號都要加1
            a++;
            while(k--)
            {
                scanf("%d", &b);
                b++;
                p[b].pre=a;
                p[b].brother=p[a].son;
                p[a].son=b;
            }
        }
        int ans;
        for(t=1; t<=n; ++t)
        {
            if(!p[t].pre)
            {
                dfs(t);
                ans=min(dp[t][0], dp[t][1]);
                break;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}






#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define inf 0x7fffffff
#define N 10100
using namespace std;    //hdu 2196  樹形dp
int vis[N], pre[N], dp[N][3];   //dp[n][m]中n是節點編號, m爲0表示從下到上節點的最大值, m爲1表示從小到上第2大值, m爲2表示從上到下的最大值
/*
題意:給你一棵樹,求樹上各個節點到其他節點的距離中的最大值
思路:先用鄰接表建樹,樹形dp
*/
struct node
{
	int v, next, w;   //表示的是一條邊
}p[N<<1];
void init()
{
	memset(pre, -1, sizeof(pre));
	memset(dp, 0, sizeof(dp));
	memset(vis, 0, sizeof(vis));
}

void dfs1(int x)     //從下到上
{
	vis[x]=1;
	int j, t, biggest, bigger;
	biggest=bigger=0;
	for(j=pre[x]; j!=-1; j=p[j].next)
	{
		if(vis[p[j].v])    //之前訪問過的祖先
			continue;
		dfs1(p[j].v);
		if(dp[p[j].v][0]+p[j].w>biggest)
		{
			bigger=biggest;
			biggest=dp[p[j].v][0]+p[j].w;
		}
		else if(dp[p[j].v][0]+p[j].w>bigger)
		{
			bigger=dp[p[j].v][0]+p[j].w;
		}
		dp[x][0]=biggest;
		dp[x][1]=bigger;
	}
	return ;
}

void dfs2(int x)   //從上到下
{
	vis[x]=1;
	int t, j, son;
	for(j=pre[x]; j!=-1; j=p[j].next)
	{
		son=p[j].v;
		if(vis[son])continue;
		dp[son][2]=(dp[son][0]+p[j].w==dp[x][0]?dp[x][1]:dp[x][0])+p[j].w;   //表示這個節點的父親節點下的其他分支的最大值
		dp[son][2]=max(dp[son][2], dp[x][2]+p[j].w);   //父親節點之上的最大值
		dfs2(p[j].v);
	}
}


int main()
{
	int n, t, j, k, a, b;
	while(~scanf("%d", &n))
	{

		k=0;
		init();
		for(t=2; t<=n; ++t)    
		{
			scanf("%d%d", &a, &b);   //無向圖
			p[k].v=t;
			p[k].w=b;
			p[k].next=pre[a];
			pre[a]=k++;
			p[k].v=a;
			p[k].w=b;
			p[k].next=pre[t];
			pre[t]=k++;
		}
		dfs1(1);  //從下到上遞推,求出dp[N][0]和dp[N][1]
		memset(vis, 0, sizeof(vis));
		dfs2(1);  //從上到下
		for(t=1; t<=n; ++t)
			printf("%d\n", max(dp[t][0], dp[t][2]));
	}
	return 0;
}








發佈了102 篇原創文章 · 獲贊 4 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章