树形dp
很容易想到的一种dp状态是dp[i][trap][fa]表示当前结点为i,经过trap个陷阱,从fa那里转移过来的最优解,虽然空间理论上只有O(n),但是要写成代码就得用vector或者map什么的。。。 明显的感觉要挂。。 (我赛后用map写600ms过了。。。数据弱么。。)多校的时候想到了这种状态。。但是没敢写T_T 4618那题也是这样 唉 太坑了T_T 以后不管怎样先写了再说T_T
附上map的代码。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <climits>
#include <ctime>
#include <numeric>
#include <vector>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <complex>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <sstream>
#include <set>
#include <stack>
#include <queue>
using namespace std;
template<class T> inline T sqr(T x) { return x * x; }
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
typedef pair<LL, LL> PLL;
typedef pair<LL, int> PLI;
typedef pair<LD, LD> PDD;
#define MP make_pair
#define PB push_back
#define sz(x) ((int)(x).size())
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define istr stringstream
#define FOR(i,n) for(int i=0;i<(n);++i)
const double EPS = 1e-6;
const int INF = 0x3fffffff;
const LL LINF = INF * 1ll * INF;
const double PI = acos(-1.0);
using namespace std;
int n,c;
vector<int> g[50005];
int vv[50005],cc[50005];
map<int,int> dp[50005][4];
int dfs(int u,int tot,int fa){
if(~fa&&dp[u][tot].find(fa)!=dp[u][tot].end()) return dp[u][tot][fa];
int ans = vv[u];
int tmp = tot+cc[u];
if(tmp==c){
if(~fa) return dp[u][tot][fa] = ans;
else return ans;
}
int sz = g[u].size();
for(int i = 0;i<sz;i++){
int v = g[u][i];
if(v==fa) continue;
ans = max(ans,dfs(v,tmp,u)+vv[u]);
}
if(~fa) return dp[u][tot][fa] = ans;
else return ans;
}
int main(void){
#ifndef ONLINE_JUDGE
freopen("/home/xing89qs/桌面/data.in","r",stdin);
#endif
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&c);
for(int i = 0;i<n;i++){
scanf("%d %d",&vv[i],&cc[i]);
g[i].clear();
for(int j = 0;j<=c;j++) dp[i][j].clear();
}
for(int i = 0;i<n-1;i++){
int a,b;
scanf("%d %d",&a,&b);
g[a].PB(b);
g[b].PB(a);
}
int ans = 0;
for(int i = 0;i<n;i++)
ans = max(ans,dfs(i,0,-1));
printf("%d\n",ans);
}
}
后来我再想想其实我可以按边来dp,因为其实dp[i][trap][fa]中i,fa这不就是表示的一个方向吗? 那么我们按边来dp考虑一下,dp[i][trap]表示沿着编号为i的边的方向,经过trap个陷阱的最优解,状态转移很显然的,看代码就知道了。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <climits>
#include <ctime>
#include <numeric>
#include <vector>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <complex>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <sstream>
#include <set>
#include <stack>
#include <queue>
using namespace std;
template<class T> inline T sqr(T x) { return x * x; }
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
typedef pair<LL, LL> PLL;
typedef pair<LL, int> PLI;
typedef pair<LD, LD> PDD;
#define MP make_pair
#define PB push_back
#define sz(x) ((int)(x).size())
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define istr stringstream
#define FOR(i,n) for(int i=0;i<(n);++i)
const double EPS = 1e-6;
const int INF = 0x3fffffff;
const LL LINF = INF * 1ll * INF;
const double PI = acos(-1.0);
using namespace std;
int n,c;
int vv[50005],cc[50005];
int first[50005],next[100005];
struct Edge{
int u,v;
} e[100005];
int dp[100005][4];
int cnt = 0;
void add(int a,int b){
e[cnt] = (Edge){a,b};
for(int i = 0;i<=c;i++) dp[cnt][i] = -1;
int tmp = first[a];
first[a] = cnt;
next[cnt++] = tmp;
}
int dfs(int ed,int trap){
if(trap==c) return 0;
if(~dp[ed][trap]) return dp[ed][trap];
int u = e[ed].u;
int v = e[ed].v;
int ans = vv[v];
int tmp = trap+cc[v];
for(int i = first[v];~i;i = next[i]){
if(e[i].v==u) continue;
ans = max(ans,vv[v]+dfs(i,tmp));
}
return dp[ed][trap] = ans;
}
int main(void){
#ifndef ONLINE_JUDGE
freopen("/home/xing89qs/桌面/data.in","r",stdin);
#endif
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&c);
for(int i = 0;i<n;i++){
scanf("%d %d",&vv[i],&cc[i]);
first[i] = -1;
}
cnt = 0;
for(int i = 0;i<n-1;i++){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
}
int ans = 0;
for(int i = 0;i<cnt;i++){
int u = e[i].u;
ans = max(ans,vv[u]+dfs(i,cc[u]));
}
printf("%d\n",ans);
}
}