【模拟试题3】【20150527】

树形DP+背包


  老师让我们补做了一下PKUSC那周的题目= =

  这次好像是树形DP的专题?感觉题目还是很棒的,值得将来再回头学习。

Cateran

  树形状压DP,其实在看题解之前我似乎并没有搞懂这题在干什么……

  对于节点 i ,我们考虑f[i][j]表示 i 这棵子树中,分部包含情况为 j 的最大收益,因为一个分部管的是从x到根的所有点,所以对于一个点来说,管它的就是子树中的所有分部,所以就可以dp啦~依次枚举每个儿子的子树中有哪些分部,用一个辅助数组,我们可以搞:

  c[j]=f[x][j];

  c[j]=max(c[j],f[y][k]+f[x][j^k]);

  f[x][j]=c[j];

依次搞下来即可。

  初始化就是分部全部在 x 节点。计算完后要加上符合的收益(T种中的某一些……)

 1 //20150527 cateran
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 #define pb push_back
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
17     return r*v;
18 }
19 const int N=4100;
20 /*******************template********************/
21 
22 int head[110],nxt[220],to[220],cnt;
23 void add(int x,int y){
24     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
25     to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt;
26 }
27 int n,m,T,a[110][15],b[N],c[N];
28 int f[110][N];
29 
30 void dfs(int x,int fa){
31     rep(j,(1<<m)){
32         f[x][j]=0;
33         rep(i,m) if (j&(1<<i)) f[x][j]-=a[x][i+1];
34 //        printf("f[%d][%d]=%d\n",x,j,f[x][j]);
35     }
36     int y;
37     for(int i=head[x];i;i=nxt[i])
38         if ((y=to[i])!=fa){
39             dfs(y,x);
40             rep(j,(1<<m)) c[j]=f[x][j];
41             rep(j,(1<<m))
42                 for(int k=j;k;k=(k-1)&j)
43                     c[j]=max(c[j],f[y][k]+f[x][j^k]);
44             rep(j,1<<m) f[x][j]=c[j];
45         }
46     rep(i,1<<m)
47         for(int k=i;k;k=(k-1)&i) f[x][i]+=b[k];
48 //    rep(i,1<<m) printf("f[%d][%d]=%d\n",x,i,f[x][i]);
49 }
50 int main(){
51 #ifndef ONLINE_JUDGE
52     freopen("cateran.in","r",stdin);
53     freopen("cateran.out","w",stdout);
54 #endif
55     n=getint(); m=getint();
56     F(i,2,n){
57         int x=getint(),y=getint();
58         add(x,y);
59     }
60     F(i,1,n) F(j,1,m) a[i][j]=getint();
61     T=getint();
62     F(i,1,T){
63         int v=getint(),c=getint(),now=0,x;
64         F(j,1,c){
65             x=getint();
66             now|=1<<(x-1);
67         }
68         b[now]+=v;
69     }
70     dfs(1,0);
71     printf("%d\n",f[1][(1<<m)-1]);
72     return 0;
73 }
View Code

Party

  ……傻逼题吧……f[x][0]表示邀请这个人时,这棵子树的最大收益;f[x][1]表示不邀请……

 1 //20150527 party
 2 #include<cstdio>
 3 #include<string>
 4 #include<map>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define rep(i,n) for(int i=0;i<n;++i)
10 #define F(i,j,n) for(int i=j;i<=n;++i)
11 #define D(i,j,n) for(int i=j;i>=n;--i)
12 #define pb push_back
13 using namespace std;
14 typedef long long LL;
15 inline int getint(){
16     int r=1,v=0; char ch=getchar();
17     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
18     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
19     return r*v;
20 }
21 const int N=110;
22 /*******************template********************/
23 
24 int head[N],to[N],next[N],cnt;
25 void add(int x,int y){
26     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
27 }
28 
29 int v[N],fa[N],f[N][2],n;
30 char s1[N][25],s2[N][25];
31 map<string,int>mp;
32 
33 void dfs(int x){
34     f[x][0]=0; f[x][1]=v[x];
35     for(int i=head[x];i;i=next[i]){
36         dfs(to[i]);
37         f[x][0]+=max(f[to[i]][0],f[to[i]][1]);
38         f[x][1]+=f[to[i]][0];
39     }
40 }
41 int main(){
42 #ifndef ONLINE_JUDGE
43     freopen("party.in","r",stdin);
44     freopen("party.out","w",stdout);
45 #endif
46 //    ios::sync_with_stdio(false);
47     cin >> n;
48     F(i,1,n){
49         cin >> s1[i] >> v[i] >> s2[i];
50         mp[s1[i]]=i;
51     }
52     F(i,1,n){
53         fa[i]=mp.find(s2[i])->second;
54         add(fa[i],i);
55     }
56 //    F(i,1,n) printf("%d ",fa[i]); puts("");
57     int ans=0;
58     F(i,1,n) if (fa[i]==0){
59         dfs(i);
60         ans+=max(f[i][0],f[i][1]);
61     }
62     printf("%d\n",ans);
63     return 0;
64 }
View Code

Railway

  无向图最大权路径覆盖= =?然而其实并不是费用流之类……

  f[x][0]表示x是孤立点时,x子树内最大收益;

  f[x][1]表示x子树内有一条链与它相连;

  f[x][2]表示x子树内有两条链与它相连

  前两种情况是可以继续向上连的,而第三种情况就不可以了……

  转移……Orz regina8023 其实是个贪心。

  先假设所有点都没跟x连,得到f[x][0],然后再考虑一下将某个儿子连到父亲,会使答案改变多少,贪心地选出1-2个,即可得到f[x][1]和f[x][2]。

 1 //20150527 railway
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 #define pb push_back
12 using namespace std;
13 typedef long long LL;
14 inline int getint(){
15     int r=1,v=0; char ch=getchar();
16     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
17     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
18     return r*v;
19 }
20 const int N=2010,M=4010,INF=0x3f3f3f3f;
21 /*******************template********************/
22 
23 int head[N],nxt[M],to[M],l[M],cnt;
24 void add(int x,int y,int z){
25     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; l[cnt]=z;
26     to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt; l[cnt]=z;
27 }
28 
29 int n,ans;
30 
31 int f[N][3],fa[N];
32 void dfs(int x){
33     f[x][0]=f[x][1]=0;
34     int max1=-INF,max2=-INF;
35     for(int i=head[x];i;i=nxt[i])
36         if (to[i]!=fa[x]){
37             fa[to[i]]=x;
38             dfs(to[i]);
39             int t=max(f[to[i]][1],f[to[i]][2]);
40             f[x][0]+=t;
41             f[x][1]+=t;
42             f[x][2]+=t;
43             int p=l[i]+max(f[to[i]][0],f[to[i]][1])-t;
44             if (p>max1) max2=max1,max1=p;
45             else if (p>max2) max2=p;
46         }
47     f[x][1]+=max1;
48     f[x][2]+=max1+max2;
49 }
50 
51 int main(){
52 #ifndef ONLINE_JUDGE
53     freopen("railway.in","r",stdin);
54     freopen("railway.out","w",stdout);
55 #endif
56     n=getint();
57     F(i,2,n){
58         int x=getint(),y=getint(),z=getint();
59         add(x,y,z);
60     }
61     dfs(1);
62     printf("%d\n",max(f[1][1],f[1][2]));
63     return 0;
64 }
View Code

Lamp

  树形背包。

  好像是在背包九讲的泛型背包里讲的……

  反正也是很easy的一道题……记录一下从哪里转移过来的即可

  f[x][i]表示以x为根的子树中总重量为 i 时的最大亮度和。

  g[x][i]表示以x为根的子树中,不考虑根,总重量为 i 时的最大亮度和。

  所以我们有:

    g[x][i]=max(g[x][i],g[x][j]+f[son][i-j])

    f[x][i]=g[x][i-w[x]]+l[x];

  容易发现其实用一个数组就可以了= =这里我用两个数组来表示,只是为了方便理解。

 1 //20150527 lamp
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 #define pb push_back
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
17     return r*v;
18 }
19 const int N=410;
20 /*******************template********************/
21 
22 int head[N],nxt[N],to[N],cnt;
23 void add(int x,int y){
24     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
25 }
26 int f[N][N],w[N],p[N],l[N],n,fa[N];
27 bool yes[N];
28 typedef pair<int,int> pii;
29 #define mp make_pair
30 pii from[N][N];
31 
32 void dfs(int x){
33     for(int i=head[x];i;i=nxt[i]){
34         dfs(to[i]);
35         D(j,p[x],w[to[i]]) F(k,w[to[i]],j)
36             if (f[x][j-k]+f[to[i]][k]>f[x][j]){
37                 from[x][j]=mp(to[i],k);
38                 f[x][j]=f[x][j-k]+f[to[i]][k];
39             }
40     }
41     if (x!=1){
42         D(i,p[x]+w[x],w[x]){
43             f[x][i]=f[x][i-w[x]]+l[x];
44             from[x][i]=from[x][i-w[x]];
45         }
46     }
47 }
48 void Find(int x,int y){
49     if (!x || !y) return;
50 //    cout <<"Find"<<x <<" "<<y <<endl;
51     yes[x]=1;
52     Find(from[x][y].first,from[x][y].second);
53     if (from[x][y].second) Find(x,y-from[x][y].second);
54 }
55 int main(){
56 #ifndef ONLINE_JUDGE
57     freopen("lamp.in","r",stdin);
58     freopen("lamp.out","w",stdout);
59 #endif
60     n=getint();
61     F(i,1,n){
62         fa[i]=getint(),w[i]=getint(),p[i]=getint(),l[i]=getint();
63         add(fa[i],i);
64     }
65     dfs(1);
66     Find(1,p[1]);
67     int num=0;
68     F(i,1,n) num+=yes[i];
69     printf("%d ",num);
70     printf("%d\n",f[1][p[1]]+l[1]);
71     int cnt=0;
72     F(i,1,n) if (yes[i])
73         printf("%d%c",i,(++cnt)==num ? '\n' : ' ');
74 //    F(i,1,n){F(j,1,p[i]) printf("%d ",f[i][j]); puts("");}
75 //    F(i,1,n)F(j,1,p[i]+w[i])if (from[i][j].second) printf("from[%d][%d]=%d,%d\n",i,j,from[i][j].first,from[i][j].second);
76     return 0;
77 }
View Code

 

posted @ 2015-06-04 17:04  Tunix  阅读(197)  评论(0编辑  收藏  举报