1. 程式人生 > >樹上dp入門

樹上dp入門

樹形dp就是把操作放在樹上。

1. P1352 沒有上司的舞會 ——樹的最大獨立集

題意:上司如果參加酒會,下屬就不去了。很容易想到上司和員工之間的關係就是父節點與子節點的關係,用boss[i]來儲存i的父節點編號。因為編號是1-n的嘛,我們就初始化boss[]為0,然後遍歷知道根節點,顯然,沒有父節點的那個為根節點(boss[i]==0).

狀態定義dp[i][0]為i不參加時i和他的下屬製造的最大歡樂度

dp[i][0]為i參加時i和他的下屬製造的最大歡樂度

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=6e3+10;
int a[maxn];
int n,boss[maxn],dp[maxn][2];
vector<int> E[maxn];

void dfs(int x){
	dp[x][0]=0;
	dp[x][1]=a[x];
	for(int i=0;i<E[x].size();i++){
		int tmp=E[x][i];
		dfs(tmp);
		dp[x][0]+=max(dp[tmp][0],dp[tmp][1]); //沒取父節點的值,子節點分為取或不取兩種情況,取其中值較大的那種情況
		dp[x][1]+=dp[tmp][0];  //既然去了父節點的值,子節點的值不能取了
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	int L,k;
	while(~scanf("%d%d",&L,&k)){
		if(L==0&&k==0) break;
		boss[L]=k;
		E[k].push_back(L);
	}
	for(int i=1;i<=n;i++){
		if(boss[i]==0){
			dfs(i);
			printf("%d\n",max(dp[i][0],dp[i][1]));
			break;
		}
	}
	return 0;
}

因為要排序,演算法的時間複雜度為O(nlogn) 。

#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn = 100000 + 5;

int n, t;
vector<int> sons[maxn];


int dp(int u)  //dp(u)表示讓u給上級發信最少需要多少個工人。工人也就是葉子節點
{
    if (sons[u].empty())  return 1;
    vector<int> d;
    int k = sons[u].size();
    for (int i = 0; i < k; i++)
        d.push_back(dp(sons[u][i]));
    sort(d.begin(), d.end());
    //int c = (k*t - 1) / 100 + 1; //上取整語句,等價於下邊那一句
    int c=ceil(k*t/100.0);
    //cout<<"c="<<c<<endl;
    int ans = 0;
    for (int i = 0; i < c; i++){
        ans += d[i];
        //cout<<"d["<<i<<"]="<<d[i]<<",ans="<<ans<<endl;
    }

    return ans;
}

int main()
{
    int temp;
    while (cin >> n >> t && (n || t))
    {
        for (int i = 0; i <= n; i++)
            sons[i].clear();
        for (int i = 1; i <= n; i++)
        {
            cin >> temp;
            sons[temp].push_back(i);
        }
        int ans=dp(0);
        cout << ans << endl;
    }
    return 0;
}

再次寫的程式碼,

#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
vector<int> sons[maxn];
int n,t;

int dp(int x){
    if(sons[x].empty()) return 1;
    int ans=0;
    int k=sons[x].size();
    vector<int> w;
    for(int i=0;i<k;i++){
        //cout<<"子節點:"<<sons[x][i]<<",dp(sons[x][i])="<<dp(sons[x][i])<<endl;
        w.push_back(dp(sons[x][i]));
    }
   /* for(int i=0;i<k;i++){
        cout<<"w[i]="<<w[i]<<endl;
    }*/
    sort(w.begin(),w.end());
    int c=ceil(k*t/100.0);
    //cout<<"c="<<c<<endl;
    for(int i=0;i<c;i++)
        ans+=w[i];
    return ans;
}


int main(){
    while(cin>>n>>t){
        if(n==0&&t==0) break;
        for(int i=0;i<=n;i++)
            sons[i].clear();
        int tmp;
        for(int i=1;i<=n;i++){
            cin>>tmp;
            sons[tmp].push_back(i);
        }
        cout<<dp(0)<<endl;;
    }




}