• [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp


    <题面>

    这个题真伤人

    之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰

    先来一个Tarjan的链接:$mathbb{O}$

    题目的数据比较友好:

    $dp$不对:$leq10$

    $dp$对了Tarjan不对:$40$

    都对了:$100$


    接下来就是思路

    首先观察题目。

    $n$个点$n$条边,也许有环。

    所以先以$0$为根节点(虚根,可以想象成”系统“,所有软件的依赖,无价值无内存),这样有一个好处,不用建边时特判,直接建就好了(无依赖是$0$)

    额,你要问我怎么建,从被依赖的向依赖的指一个有向边

    被依赖的$Longrightarrow$依赖的,这样建好的图便于转移

    建图结束,下面是个重头戏:缩点

    这个题缩点极为简单,你会发现,环里的点已经互相依赖,不可能依赖其他的程序(除了虚根,我们暂不考虑)

    这是我们就可以把它们打包安装。

    首先Tarjan找出这个环,打个标记(我用的用新节点下标)

    这样,我们把所有边扫一遍,凡是从环中的点出发的边起点都拽到新节点上,顺便把价值也统过去(别记重了)

    最后把新节点连到虚根上。

    还是很棒的吧?

    然后是$dp$,就是很普通的树上背包。

    $f_{i,j}$表示第$i$号节点使用$j$空间时的最大价值

    写式子为敬:

    $f_{i,j} = max limits_{w leq j , s in son_i} { f_{i,j-w}+f_{s,w} }$

    要从大往小$dp$,防止重复更新(01背包)

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #define  N 111
      5 #define  M 555
      6 using namespace std;
      7 
      8 struct STAR{
      9     int f,t,next;
     10 }rs[N*N];int fl[2*N],cnt=0;
     11 void add(int f,int t){
     12     rs[cnt].f=f;
     13     rs[cnt].t=t;
     14     rs[cnt].next=fl[f];
     15     fl[f]=cnt;
     16     cnt++;
     17 }
     18 int pom,rom;
     19 int val[2*N],cost[2*N];
     20 struct mystack{
     21     int st[2*N],tp;
     22     mystack(){
     23         tp=0;
     24         memset(st,0,sizeof st);
     25     }
     26     int top(){
     27         return st[tp-1];
     28     }
     29     void pop(){
     30         tp--;
     31     }
     32     void push(int k){
     33         st[tp]=k;
     34         tp++;
     35     }
     36     bool empty(){
     37         if(tp==0)return true;
     38         return false;
     39     }
     40 }sk;
     41 void prerun(){
     42     memset(fl,-1,sizeof fl);
     43 }
     44 int dfn[2*N],low[2*N],dep=0,bl[2*N];
     45 bool is_in[2*N],is_v[2*N],cut[2*N];
     46 void tarjan(int k){//cout<<" J "<<k<<endl;
     47     dep++;
     48     dfn[k]=low[k]=dep;
     49     int t;
     50     sk.push(k);
     51     is_in[k]=1;
     52     for(int i=fl[k];i!=-1;i=rs[i].next){
     53         t=rs[i].t;
     54         if(!dfn[t]){
     55             tarjan(t);
     56             low[k]=min(low[k],low[t]);
     57         }
     58         else{
     59             if(is_in[t]){
     60                 low[k]=min(low[k],low[t]);
     61             }
     62         }
     63     }
     64     if(low[k]==dfn[k]){
     65         if(sk.top()==k){
     66             sk.pop();
     67             is_in[k]=0;
     68             return;
     69         }
     70         int p=0;
     71         pom++;
     72         do{
     73             p=sk.top();
     74             is_in[p]=0;
     75             bl[p]=pom;
     76             sk.pop();
     77         }while(p!=k);
     78     }
     79 }
     80 int dp[2*N][M];
     81 void dfs(int k){
     82     is_v[k]=1;
     83     dp[k][0]=0;
     84     for(int i=fl[k];i!=-1;i=rs[i].next){
     85         int t=rs[i].t;
     86         if(!is_v[t]){
     87             dfs(t);
     88             for(int w=rom;w>=0;w--){
     89                 for(int m=0;m<=rom;m++){
     90                     if(w-m>=0)
     91                         dp[k][w]=max(dp[k][w],dp[k][w-m]+dp[t][m]);
     92                 }
     93             }
     94         }
     95     }
     96     for(int i=rom;i>=0;i--)
     97         if(i-cost[k]>=0)
     98             dp[k][i]=dp[k][i-cost[k]]+val[k];
     99         else 
    100             dp[k][i]=0;
    101 }
    102 int ans=0;
    103 int main(){
    104     int a,beg;
    105     prerun();
    106     scanf("%d%d",&pom,&rom);beg=pom;
    107     for(int i=1;i<=pom;i++)
    108         scanf("%d",&cost[i]);
    109     for(int i=1;i<=pom;i++)
    110         scanf("%d",&val[i]);
    111     for(int i=1;i<=pom;i++){
    112         scanf("%d",&a);
    113         add(a,i);
    114     }
    115     for(int i=0;i<=beg;i++){
    116         if(!dfn[i])tarjan(i);
    117     }
    118     for(int i=0;i<cnt;i++){
    119         int fo=rs[i].f,to=rs[i].t;
    120         if(bl[fo]!=0){//cout<<"Cut"<<rs[i].f<<endl;
    121             if(cut[fo]==0){
    122                 val[bl[fo]]+=val[fo];
    123                 cost[bl[fo]]+=cost[fo];
    124                 cut[fo]=1;
    125             }
    126             add(bl[fo],to);
    127             
    128         }
    129     }
    130     for(int i=1;i<=beg;i++){
    131         if(bl[i]!=0){
    132             is_v[i]=1;
    133             fl[i]=-1;
    134         }
    135     }
    136     for(int i=beg+1;i<=pom;i++){
    137         add(0,i);
    138     }
    139     dfs(0);
    140     for(int i=0;i<=rom;i++){
    141         ans=max(ans,dp[0][i]);
    142     }
    143     printf("%d
    ",ans);
    144     return 0;
    145 }
    Code
    Miemeng真的蒻
  • 相关阅读:
    洛谷 P1521 求逆序对
    火柴棒等式(2008年NOIP全国联赛提高组)
    扫雷游戏
    数字统计(2010年NOIP全国联赛普及组)
    祖瑪
    巧克力棒&&新年的巧克力棒
    关押罪犯(2010年NOIP全国联赛提高组)
    大整数运算||高精度运算
    國王遊戲(2012年NOIP全国联赛提高组)
    谁拿了最多奖学金(2005提高组第一题)
  • 原文地址:https://www.cnblogs.com/kalginamiemeng/p/11180393.html
Copyright © 2020-2023  润新知