今天我们来学一下树状DP
树状DP 一听就明白,树上的DP,父亲的状态要根据儿子的状态来确定,而树这种东西呢,一般DFS一遍就可以了。
先来两个题吧。
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6456 | Accepted: 3722 |
Description
Input
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
Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
Sample Output
5
Source
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)
#endif
using 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]选x
int 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();
#endif
gn(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 HandsomeHow
time_t endttt = clock();
debug("time: %d\n",(int)(endttt - beginttt));
#endif
return 0;
}
Time Limit: 2000MS | Memory Limit: 65536K | |
Total 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 2 Aland 10 Boland 20 Aland Coland 15 #
Sample Output
20
Source
题意:给定一些结点,父子关系,以及结点的价格,然后如果买下了某结点就获得了以这个点为根的整棵树,问拥有至少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)
#endif
using 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();
#endif
char 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;
}
} //read
fur(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 HandsomeHow
time_t endttt = clock();
debug("time: %d\n",(int)(endttt - beginttt));
#endif
return 0;
}