hdu 4276 The Ghost Blows Light
这个题是树形dp比赛的时候一直超时,囧,最后将代码进行了优化,然后就过了
我的思路是,先将1到n的边先走,将走过的边时间改为0,然后其他的边都得走二次!剩下的就是简单的tree dp了,当时的代码太乱了!以至于超时!
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> using namespace std; #define N 110 #define M 510 int n,t; struct note { int v,next,time; }edge[N*2]; int dat[N],head[N],kk; void init() { kk = 1; memset(head,-1,sizeof(head)); } void add(int fa,int son,int val) { edge[kk].time = val; edge[kk].v = son; edge[kk].next = head[fa]; head[fa] = kk++; } int temp; bool dfs(int rt,int fa) { if(rt == n) return 1; for(int i = head[rt];i != -1;i = edge[i].next) { int son = edge[i].v; if(son == fa) continue; if( dfs(son,rt) ) { temp += edge[i].time; edge[i].time = 0; return 1; } } return 0; } int dp[N][M];//表示第i个点消耗M时间时的耗费 int mma[N][M]; void dfs2(int rt,int fa) { for(int i = head[rt];i != -1;i = edge[i].next) { int son = edge[i].v; if(son == fa) continue; dfs2(son,rt); int cost = edge[i].time*2; /** 第二层循环的j从大到小循环是因为cost肯能是0 这儿使用的是滚动数组计数,当cost=0时,dp[rt][i]就会使用本次的dp[rt][i];造成错误 从大到小循环,可以解决的问题是,最开始使用的dp[rt][i]必是上一次的, 且以后不会再用点dp[rt][i]; */ for(int i = t;i >= cost;i--) for(int j = i-cost;j >= 0;j--)//这个顺序怎么会有问题??? //for(int j = 0;j <= i-cost;j++) dp[rt][i] = max(dp[rt][i],dp[rt][j] + dp[son][i - cost - j]); } for(int i = 0;i <= t;i++) dp[rt][i] += dat[rt]; } int main() { while(scanf("%d%d",&n,&t) != EOF) { init(); int a,b,v; for(int i = 1;i < n;i++) { scanf("%d%d%d",&a,&b,&v); add(a,b,v); add(b,a,v); } for(int i = 1;i <= n;i++) scanf("%d",&dat[i]); memset(dp,0,sizeof(dp)); temp = 0; dfs(1,-1); if(temp > t) { printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); continue; } t-= temp; dfs2(1,-1); printf("%d\n",dp[1][t]); } return 0; } /* 2 1 1 2 1 1 1 5 10 1 2 2 2 3 2 2 5 3 3 4 3 1 2 3 4 5 5 10 1 2 2 2 3 2 2 5 8 3 4 3 1 2 3 4 5 5 10 1 2 3 2 3 2 2 5 8 3 4 3 1 2 3 4 5 */
这个题应该是离散化 dp 吧
重点工作是判重问题,我的方法是:将前i个数构成的三边中第一大的和第二大的作为判重的标准!
/** 1011 */ #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <map> #include <utility> using namespace std; int dat[100]; int sum; struct note { int a,b,c; }re[1000000]; bool cmp(const note a,const note b) { return a.a < b.a || (a.a == b.a && a.b < b.b) || (a.a == b.a && a.b == b.b && a.c < b.c); } int kk; void sort(int &a,int &b,int &c) { if(a > b) swap(a,b); if(a > c) swap(a,c); if(b > c) swap(b,c); } bool check(int a,int b) { int c = sum - a - b; if(a+b > c && b + c > a && a+c > b) { //cout << a << " " << b << " " << c << "\n"; sort(a,b,c); re[kk].a = a; re[kk].b = b; re[kk].c = c; kk++; return 1; } return 0; } pair<int,int> _make_pair(int _sum,int a,int b) { int c = _sum - a - b; sort(b,a,c); if(a > b) return make_pair(a,b); return make_pair(b,a); } bool same(note a,note b) { return a.a == b.a && a.b == b.b && a.c == b.c; } int main() { int sss = 1; for(int i = 0;i < 15;i++) sss *= 3; //cout << sss; int t,n; scanf("%d",&t); while(t--) { map < pair<int ,int > , int > dp[16]; scanf("%d",&n); for(int i = 0;i < n;i++) scanf("%d",&dat[i]); sum = 0; for(int i = 0;i < n;i++) sum += dat[i]; //pair pp(0,dat[0]); dp[0] [ make_pair(dat[0],0) ] ++; dp[0] [ make_pair(0,0) ] ++; int _sum = dat[0]; for(int i = 1;i < n;i++) { _sum += dat[i]; map<pair<int,int>,int>::iterator it = dp[i-1].begin(); for(;it!=dp[i-1].end();++it) { pair <int,int> p = it->first; dp[i][_make_pair(_sum,p.first+dat[i],p.second)]++; dp[i][_make_pair(_sum,p.first,p.second+dat[i])]++; dp[i][_make_pair(_sum,p.first,p.second)]++; } } int ree = 0; kk = 0; map<pair<int,int>,int>::iterator it = dp[n-1].begin(); for(;it!=dp[n-1].end();++it) { pair <int,int> p = it->first; check(p.first,p.second) ; } sort(re,re+kk,cmp); if(kk == 0) ree = 0; else { ree = 1; for(int i = 1;i < kk;i++) { if( !same(re[i],re[i-1]) ) ree++; } } cout << ree << "\n"; } return 0; }