树状DP

来源:互联网 发布:mysql的insert语句 编辑:程序博客网 时间:2024/05/29 18:59

今天我们来学一下树状DP

树状DP 一听就明白,树上的DP,父亲的状态要根据儿子的状态来确定,而树这种东西呢,一般DFS一遍就可以了。

先来两个题吧。


Anniversary party
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 6456 Accepted: 3722

Description

There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.

Input

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go N – 1 lines that describe a supervisor relation tree. Each line of the tree specification has the form: 
L K 
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line 
0 0 

Output

Output should contain the maximal sum of guests' ratings.

Sample Input

711111111 32 36 47 44 53 50 0

Sample Output

5

Source

Ural State University Internal Contest October'2000 Students Session

POJ2342 题意很简单,给定一颗树,每个结点有个值,在一条边上的点不能同时选,然后选结点,这些结点的值的和最大是多少。

解法:开个数组dp[MAXN][2],dp[u][1]以这个结点为根,选这个结点的情况下和最大是多少,dp[u][0]表示以这个结点为根,不选这个结点的和最大是多少。

那么很显然 dp[u][1] = sum(dp[v][0]) + value[u]  (v是u的子结点),dp[u][0] = sum(max(dp[v][0],dp[v][1])) (v是u的子结点)

然后我们就从根结点dfs一下,回溯的时候更新dp值就好了,然后结果自然是max(dp[root][0],dp[root][1]).

代码:

//************************************************************************////*Author : Handsome How                                                 *////************************************************************************////#pragma comment(linker, "/STA    CK:1024000000,1024000000")#include <vector>#include <map>#include <set>#include <queue>#include <stack>#include <algorithm>#include <sstream>#include <iostream>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <string>#include <ctime>#if defined(_MSC_VER) || __cplusplus > 199711L#define aut(r,v) auto r = (v)#else#define aut(r,v) __typeof(v) r = (v)#endif#define foreach(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)#define fur(i,a,b) for(int i=(a);i<=(b);i++)#define furr(i,a,b) for(int i=(a);i>=(b);i--)#define cl(a) memset((a),0,sizeof(a))#define min(a,b) ((a)<(b)?(a):(b))#define max(a,b) ((a)>(b)?(a):(b))#ifdef HandsomeHow#define debug(...) fprintf(stderr, __VA_ARGS__)#define dbg(x) cout << #x << " = " << x << endl#else#define debug(...)#define dbg(x)#endifusing namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair <int, int> pii;const int inf=0x3f3f3f3f;const double eps=1e-8;const int mod=1000000007;const double pi=acos(-1);inline void gn(long long&x){    int sg=1;char c;while(((c=getchar())<'0'||c>'9')&&c!='-');c=='-'?(sg=-1,x=0):(x=c-'0');    while((c=getchar())>='0'&&c<='9')x=x*10+c-'0';x*=sg;}inline void gn(int&x){long long t;gn(t);x=t;}inline void gn(unsigned long long&x){long long t;gn(t);x=t;}int gcd(int a,int b){return a? gcd(b%a,a):b;}ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}// (づ°ω°)づe★//-----------------------------------------------------------------int n;const int maxn = 6666;int v[maxn][2];//v[i][0] 不选x  v[i][1]选xint p[maxn]; vector<int>son[maxn];bool vis[maxn];void dfs(int root){if(vis[root]) return;vis[root] = true;if(son[root].size() == 0) return;int sz = son[root].size();for(int i = 0; i < sz; ++i) dfs(son[root][i]);for(int i = 0; i < sz; ++i){int tmp = son[root][i];v[root][1] += v[tmp][0];v[root][0] += max(v[tmp][0],v[tmp][1]);}}int main(){#ifdef HandsomeHow    //freopen("E:\\data.in","r",stdin);    //freopen("E:\\data.out","w",stdout);    time_t beginttt = clock();#endifgn(n);memset(v,0x3f,sizeof(v));fur(i,1,6000) son[i].clear();cl(v);cl(p);cl(vis);fur(i,1,n) gn(v[i][1]);int a,b;fur(i,2,n){gn(a);gn(b);p[a] = b;son[b].push_back(a);}int root = 1;while(p[root]!=0)root = p[root];dfs(root);printf("%d\n",max(v[root][1],v[root][0]));#ifdef HandsomeHowtime_t endttt = clock();    debug("time: %d\n",(int)(endttt - beginttt));#endifreturn 0;}


Bribing FIPA
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 4807 Accepted: 1509

Description

There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (International Programming World Cup). Benjamin Bennett, the delegation of Diamondland to FIPA, is trying to seek other delegation's support for a vote in favor of hosting IWPC in Diamondland. Ben is trying to buy the votes by diamond gifts. He has figured out the voting price of each and every country. However, he knows that there is no need to diamond-bribe every country, since there are small poor countries that take vote orders from their respected superpowers. So, if you bribe a country, you have gained the vote of any other country under its domination (both directly and via other countries domination). For example, if C is under domination of B, and B is under domination of A, one may get the vote of all three countries just by bribing A. Note that no country is under domination of more than one country, and the domination relationship makes no cycle. You are to help him, against a big diamond, by writing a program to find out the minimum number of diamonds needed such that at least m countries vote in favor of Diamondland. Since Diamondland is a candidate, it stands out of the voting process.

Input

The input consists of multiple test cases. Each test case starts with a line containing two integers n (1 ≤ n ≤ 200) and m (0 ≤ m ≤ n) which are the number of countries participating in the voting process, and the number of votes Diamondland needs. The next n lines, each describing one country, are of the following form:

CountryName DiamondCount DCName1 DCName1 ...

CountryName, the name of the country, is a string of at least one and at most 100 letters and DiamondCount is a positive integer which is the number of diamonds needed to get the vote of that country and all of the countries that their names come in the list DCName1 DCName1 ... which means they are under direct domination of that country. Note that it is possible that some countries do not have any other country under domination. The end of the input is marked by a single line containing a single # character.

Output

For each test case, write a single line containing a number showing the minimum number of diamonds needed to gain the vote of at least m countries.

Sample Input

3 2Aland 10Boland 20 AlandColand 15#

Sample Output

20

Source

Tehran 2006


POJ3345


题意:给定一些结点,父子关系,以及结点的价格,然后如果买下了某结点就获得了以这个点为根的整棵树,问拥有至少m个结点的最小价格。

解法:首先题目保证了没有环,但是并没有保证只有一棵树,所有我们建完树以后要先把这些根结点都弄到一个总结点下面,接着用dp[u][i]表示以u为结点,获得i个结点的最低消费,然后在每个结点跑一遍01背包就好了。

代码:

//************************************************************************////*Author : Handsome How                                                 *////************************************************************************////#pragma comment(linker, "/STA    CK:1024000000,1024000000")#include <vector>#include <map>#include <set>#include <queue>#include <stack>#include <algorithm>#include <sstream>#include <iostream>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <string>#include <ctime>#if defined(_MSC_VER) || __cplusplus > 199711L#define aut(r,v) auto r = (v)#else#define aut(r,v) __typeof(v) r = (v)#endif#define foreach(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)#define fur(i,a,b) for(int i=(a);i<=(b);i++)#define furr(i,a,b) for(int i=(a);i>=(b);i--)#define cl(a) memset((a),0,sizeof(a))#define min(a,b) ((a)<(b)?(a):(b))#define max(a,b) ((a)>(b)?(a):(b))#ifdef HandsomeHow#define debug(...) fprintf(stderr, __VA_ARGS__)#define dbg(x) cout << #x << " = " << x << endl#else#define debug(...)#define dbg(x)#endifusing namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair <int, int> pii;const int inf=0x3f3f3f3f;const double eps=1e-8;const int mod=1000000007;const double pi=acos(-1);inline void gn(long long&x){    int sg=1;char c;while(((c=getchar())<'0'||c>'9')&&c!='-');c=='-'?(sg=-1,x=0):(x=c-'0');    while((c=getchar())>='0'&&c<='9')x=x*10+c-'0';x*=sg;}inline void gn(int&x){long long t;gn(t);x=t;}inline void gn(unsigned long long&x){long long t;gn(t);x=t;}int gcd(int a,int b){return a? gcd(b%a,a):b;}ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}// (づ°ω°)づe★//-----------------------------------------------------------------stringstream ss;int dp[222][222] = {0};//dp[i][j]表示贿赂i国家j个国家需要的最少的价格int sz[222]; int n,m,cnt;map<string,int>id;vector<int>son[222];vector<int>root;int p[222];void init(){ss.clear();cnt = 0;root.clear();id.clear();fur(i,0,202) son[i].clear();fur(i,0,202) sz[i] = 1;fur(i,0,202) p[i] = i;}void dfsf(int root){for(int i = 0; i < son[root].size(); ++i) {dfsf(son[root][i]);sz[root] += sz[son[root][i]];}for(int i = 2; i <= sz[root]; ++i) dp[root][i] = dp[root][1];}void dfs(int root){for(int i = 0; i < son[root].size(); ++i){int tmpson = son[root][i];dfs(tmpson);for(int j = sz[root]; j >=1; --j){for(int k = 1; k <= sz[tmpson] && k <= j; ++k){if(dp[root][j-k]+dp[tmpson][k]<dp[root][j])dp[root][j] = dp[root][j-k] + dp[tmpson][k];} //树上的01背包 }}}int main(){#ifdef HandsomeHow    //freopen("E:\\data.in","r",stdin);    //freopen("E:\\data.out","w",stdout);    time_t beginttt = clock();#endifchar tmp[200000];string name;while(cin>>n>>m){getchar();init();fur(i,1,n){ss.clear(); gets(tmp);ss<<tmp; ss>>name;if(!id.count(name))id[name] = ++cnt;int t = id[name];ss>>dp[t][1];while(ss>>name){if(!id.count(name))id[name] = ++cnt;int tson = id[name];son[t].push_back(tson);p[tson] = t;}}//readfur(i,1,n) if(p[i] == i) {p[i] = 0;son[0].push_back(i);}dfsf(0);//找到每个结点的大小并初始化dp[u][i] for(int i = 1; i <= sz[0]; ++i) dp[0][i] = inf;dfs(0);int ans = dp[0][m];cout<<ans<<endl;}#ifdef HandsomeHowtime_t endttt = clock();    debug("time: %d\n",(int)(endttt - beginttt));#endifreturn 0;}


  

0 0