• 洛谷p2515 树形DP + Tarjan


    这两天本来应该刷刷杭电的题,周末想着放松一下,就研究了一波入门哈希和tarjan。

    洛谷上找了这题,tarjan套个模板写得很快,这个再次建图加DP花了好多时间才看懂......

    杭电的题来不及刷啦嘿嘿嘿 罗总在线催补题doge

    说实话这题一上来思路比较清楚,然而tarjan之后还是照搬了不少题解区内容。

    主要是tarjan结束后,通过belong以及依赖关系,直接反向建图,秀了我一脸。果然还是摆脱不了菜~

    来个图好理解.png  ------------------------------------------------------------------------------------------------ 

    题解的大部分都是参考红色数字再建图。                                                                                |

    还看到一篇用floyd缩点的好像很有趣。那就学习一下floyd去了。hdu暂时拜拜hhh                 |

    一想到明天周二 又要白给就很烦555                                                                                       |

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<string>
      5 #include<vector>
      6 #include<iomanip>
      7 #include<cstdio>
      8 
      9 #define INF 1e9
     10 using namespace std;
     11 int n, m;
     12 int t[110];
     13 int low[110];
     14 
     15 int cnt;
     16 int now;
     17 int stop;//
     18 int S[110];//模拟栈 
     19 bool instack[110];
     20 vector<int> v[110];
     21 
     22 int w[110];//cost
     23 int val[110];//value
     24 int rely[110];//依赖关系 
     25 
     26 vector<int> T[110];//记录强连通分量 
     27 int belong[110];//判断该点属于哪一强连通分量 
     28 
     29 int dp[110][510];//
     30 
     31 void initialize()
     32 {
     33     cnt = now = stop = 0;
     34     memset(instack, false, sizeof(instack));
     35     memset(t, 0, sizeof(t));
     36     memset(belong, 0, sizeof(belong)); 
     37     memset(dp, 0, sizeof(dp)); 
     38     for(int i = 0 ; i <= 100 ; i++){
     39         v[i].clear();
     40         T[i].clear();
     41     }
     42     
     43 }
     44 
     45 void tarjan(int x)
     46 {
     47     S[++stop] = x;//入栈 
     48     t[x] = low[x] = ++now;
     49     instack[x] = true;
     50     
     51     for(int i = 0 ; i < v[x].size() ; i++){
     52         int nxt = v[x][i];
     53         if(t[nxt]){
     54             if(instack[nxt] && t[nxt] < t[x]){
     55                 low[x] = t[nxt];//
     56             }
     57         }else{
     58             tarjan(nxt);
     59             low[x] = min(low[x], low[nxt]);
     60         }        
     61     }
     62     if(low[x] == t[x]){
     63         cnt++;
     64         int j;
     65         do{
     66             j = S[stop--];
     67             instack[j] = false;
     68             belong[j] = cnt;
     69         }while(j != x);        
     70     }
     71 }
     72 //f[u][i]为在节点u的子树内,费用限制为i的条件下能取到的最大价值
     73 void dfs_dp(int *cost, int *value, int u)////////
     74 {
     75     for(int i = cost[u] ; i <= m ; i++){
     76         dp[u][i] = value[u];//不是val[u]!! 此处下标已改为染色后 
     77     }
     78     for(int i = 0 ; i < T[u].size() ; i++){
     79         int v = T[u][i];
     80         dfs_dp(cost, value, v);
     81         for(int j = m - cost[u] ; j >= 0 ; j--){
     82             for(int q = 0 ; q <= j ; q++){
     83                 dp[u][j + cost[u]] = max(dp[u][j + cost[u]], dp[u][j + cost[u] - q] + dp[v][q]);
     84                 //后者:其他位置节省开支,允许u的子节点v得到部分分配                
     85             }            
     86         }
     87     }
     88 }
     89 
     90 void dp_solve()
     91 {        
     92     int cost[110], value[110];
     93     int check[110];
     94     for(int i = 0 ; i <= n ; i++){
     95         cost[i] = value[i] = check[i] = 0;
     96     }
     97     
     98     for(int i = 1 ; i <= n ; i++){
     99         cost[belong[i]] += w[i];
    100         value[belong[i]] += val[i];//缩点
    101         if(!rely[i] || belong[rely[i]] == belong[i])    continue;
    102         T[belong[rely[i]]].push_back(belong[i]);///
    103         check[belong[i]]++;
    104     }
    105     ///神仙之反向建边之花了好几个小时才看懂系列 
    106     for(int i = 1 ; i <= n ; i++){
    107         if(!check[belong[i]]){
    108             T[0].push_back(belong[i]);
    109         }
    110     }//无头则连至虚拟节点 
    111     
    112     dfs_dp(cost, value, 0);
    113     
    114     printf("%d
    ",dp[0][m]);
    115 }
    116 
    117 int main(){
    118     scanf("%d%d",&n,&m);
    119     for(int i = 1 ; i <= n ; i++){
    120         scanf("%d",&w[i]);
    121     }
    122     
    123     for(int i = 1 ; i <= n ; i++){
    124         scanf("%d",&val[i]);
    125     }
    126     
    127     initialize();
    128     
    129     for(int i = 1 ; i <= n ; i++){
    130         scanf("%d",&rely[i]);
    131         if(rely[i]){
    132             v[rely[i]].push_back(i);//建边
    133         }
    134     }
    135     
    136     for(int i = 1 ; i <= n ; i++){
    137         if(!t[i]){
    138             tarjan(i);        
    139         }
    140     }    
    141     dp_solve();
    142     
    143     return 0;
    144 }
    145 /*
    146 12 2
    147 1 1 1 1 1 1 1 1 1 1 11 1
    148 1 1 1 11 1 1 1 1 1 1 1 1
    149 0 1 1 1 4 4 5 10 8 9 0 11
    150 */
  • 相关阅读:
    省级联动(使用ajax实现)
    java学习之 反射
    自己写的代码生成器
    java中关于StackTraceElement的使用
    在Java中判断数组中包含某个元素的几种方式的比较
    android PopupWindow 点击外面消失
    android获取textview的行数
    多线程关于腾讯笔试题
    FrameLayout的点击问题
    自定义SnackBar
  • 原文地址:https://www.cnblogs.com/ecustlegendn324/p/13517922.html
Copyright © 2020-2023  润新知