zoukankan      html  css  js  c++  java
  • 【模拟试题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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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 ? '
    ' : ' ');
    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
    ",i,j,from[i][j].first,from[i][j].second);
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    git 拉取开发代码
    android webview
    H5 元素定位
    Python中模块
    服务器1
    活动
    宝塔面板-阿里部署
    最新版Xshell、Xftp注册机NetSarang
    最新版Navicat Premium激活,附激活工具
    9月29更新美版T-mobile版本iPhone7代和7P有锁机卡贴解锁方法
  • 原文地址:https://www.cnblogs.com/Tunix/p/4552351.html
Copyright © 2011-2022 走看看