• codevs 1423 骑士


    题目描述 Description

    Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。

    最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。

    骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。

    战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。

    为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

    输入描述 Input Description

    第一行包含一个正整数N,描述骑士团的人数。

    接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。

    输出描述 Output Description

    应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

    样例输入 Sample Input
    3
    10 2
    20 3
    30 1
    样例输出 Sample Output
    30
    数据范围及提示 Data Size & Hint

    对于30%的测试数据,满足N ≤  10;

    对于60%的测试数据,满足N ≤  100;

    对于80%的测试数据,满足N ≤  10 000。

    对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于   1 000 000的正整数。


      这道题很容易就可以想到树形dp,但是会出现环,就先把树上进行树形动规,然后再在

    环上进行dp,环上的dp就从一个地方切开,然后增加一个状态,选第一个点和不选第一个点

    关于树形dp还是再说两句,用f[i]表示i骑士选的最大战斗力(仅限这棵子树),g[i]表示不选

    i骑士

      得到了方程:

      f[i] = sum{g[son[i][j]]};

      g[i] = sum{max(g[son[i][j]], f[son[i][j]])};

    (注:son[i][j]表示i节点的第j个子节点的编号,实际编程中可直接用存图的方式来储存)


    Code
      1 /**
      2  * codevs.cn
      3  * Problem#1423
      4  * Accepted
      5  * Time:1478ms
      6  * Memory:58768k
      7  */
      8 #include<iostream>
      9 #include<cstdio>
     10 #include<cstring>
     11 #include<stack>
     12 #include<vector>
     13 using namespace std;
     14 typedef bool boolean;
     15 template<typename T>
     16 void readInteger(T& u){
     17     char x;
     18     while(!isdigit((x = getchar())));
     19     for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
     20     ungetc(x, stdin);
     21 }
     22 typedef class Edge{
     23     public:
     24         int end;
     25         int next;
     26         Edge(const int end = 0, const int next = 0):end(end),next(next){}
     27 }Edge;
     28 int ce;
     29 int *h;
     30 Edge* edge;
     31 inline void addEdge(int from, int end){
     32     edge[++ce] = Edge(end, h[from]);
     33     h[from] = ce;
     34 }
     35 int cc;
     36 int *visitID;
     37 int *exitID;
     38 boolean *visited;
     39 boolean *inStack;
     40 int entryed;
     41 stack<int> sta;
     42 vector<int> *start;
     43 void getSonMap(int end){
     44     vector<int> buf;
     45     int now = -1;
     46     int exits = 0;
     47     while(now != end){
     48         now = sta.top();
     49         inStack[now] = false;
     50         exits++;
     51         buf.push_back(now);
     52         sta.pop();
     53     }
     54     if(exits > 1){
     55         for(int i = 0; i < exits; i++){
     56             start[cc].push_back(buf[i]);
     57         }
     58         cc++;
     59     }
     60 }
     61 void Tarjan(const int pi){
     62     int index = h[pi];
     63     visitID[pi] = ++entryed;
     64     exitID[pi] = visitID[pi];
     65     visited[pi] = true;
     66     inStack[pi] = true;
     67     sta.push(pi);
     68     while(index != 0){
     69         if(!visited[edge[index].end]){
     70             Tarjan(edge[index].end);
     71             exitID[pi] = min(exitID[pi],exitID[edge[index].end]);
     72         }else if(inStack[edge[index].end]){
     73             exitID[pi] = min(exitID[pi],visitID[edge[index].end]);
     74         }
     75         index = edge[index].next;
     76     }
     77     if(exitID[pi] == visitID[pi]){
     78         getSonMap(pi);
     79     }
     80 }
     81 int n;
     82 int *v;
     83 long long *f;
     84 long long *g;
     85 inline void init(){
     86     readInteger(n);
     87     v = new int[(const int)(n + 1)];
     88     edge = new Edge[(const int)(n + 1)];
     89     h = new int[(const int)(n + 1)];
     90     visited=new boolean[(const int)(n+1)];
     91     visitID=new int[(const int)(n+1)];     
     92     exitID =new int[(const int)(n+1)];      
     93     inStack=new boolean[(const int)(n+1)];
     94     start = new vector<int>[(const int)(n / 2 + 1)];
     95     f = new long long[(const int)(n + 1)];
     96     g = new long long[(const int)(n + 1)];
     97     memset(h, 0, sizeof(int) * (n + 1));
     98     memset(visited,false,sizeof(boolean)*(n+1));
     99     memset(inStack,false,sizeof(boolean)*(n+1)); 
    100     for(int i = 1,e; i <= n; i++){
    101         readInteger(v[i]);
    102         readInteger(e);
    103         addEdge(e, i);
    104     }
    105 }
    106 void tree_dp(int node, int last){
    107     f[node] = v[node];
    108     g[node] = 0;
    109     for(int i = h[node]; i != 0; i = edge[i].next){
    110         int e = edge[i].end;
    111         if(e == last || !(visited[e]))    continue;
    112         tree_dp(e, node);
    113         f[node] += g[e];
    114         g[node] += max(f[e], g[e]);
    115     }
    116 }
    117 #define int long long
    118 long long *fc[2];
    119 long long *gc[2];
    120 long long** c[4] = {&fc[0], &fc[1], &gc[0], &gc[1]};
    121 int circle_dp(int index){
    122     int result = 0;
    123     for(int i = 0; i < 4; i++){
    124         *c[i] = new int[(const int)(start[index].size() + 1)];
    125         memset(*c[i], 0, sizeof(int) * (start[index].size() + 1));
    126     }
    127     for(int k = 0; k < 2; k++){
    128         fc[k][1] = (k == 0)?(g[start[index][0]]):(f[start[index][0]]);
    129         gc[k][1] = (k == 1)?(g[start[index][0]]):(g[start[index][0]]);
    130         for(int i = 2; i <= start[index].size(); i++){
    131             fc[k][i] = gc[k][i - 1] + f[start[index][i - 1]];
    132             gc[k][i] = max(gc[k][i - 1], fc[k][i - 1]) + g[start[index][i - 1]];
    133         }
    134         int e = start[index][start[index].size() - 1];
    135         int s = start[index].size();
    136         fc[k][s] = (k == 0)?(f[e] + gc[k][s - 1]):(0);
    137         gc[k][s] = (k == 1)?(g[e] + max(gc[k][s - 1], fc[k][s - 1])):(0);
    138         result = max(result, fc[k][s]);
    139         result = max(result, gc[k][s]);
    140     }
    141     return result;
    142 }
    143 #undef int
    144 int main(){
    145     init();
    146     for(int i = 1; i <= n; i++)
    147         if(!visited[i])
    148             Tarjan(i);
    149     delete[] visitID;
    150     delete[] exitID;
    151     delete[] inStack;
    152     memset(visited, true, sizeof(boolean) * (n + 1));
    153     for(int k = 0; k < cc; k++)
    154         for(int i = 0; i < start[k].size(); i++){
    155             visited[start[k][i]] = false;
    156         }
    157     for(int k = 0; k < cc; k++)
    158         for(int i = 0; i < start[k].size(); i++)
    159             tree_dp(start[k][i], 0);
    160     delete[] visited;
    161     long long result = 0;
    162     for(int k = 0; k < cc; k++)
    163         result += circle_dp(k);
    164     cout<<result;
    165     return 0;
    166 }

      写得有点复杂,不过这都不重要(笑)

    第一次ac省选的(水)题,好开心

  • 相关阅读:
    EasyUI 清空表格
    【21年01月DW打卡】Task02
    【BUG12】排查解决一个锁超时 "MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction" 的SQL问题
    【20年12月DW打卡】joyful-pandas
    【21年01月DW打卡】Task01
    【12月DW打卡】joyful-pandas
    【12月DW打卡】joyful-pandas
    【Pandas】resample重采样中的周‘W’按周日开始为一周('W'的频率偏移默认为‘right’、使用label = 'left' 重设)+ 常用freq的别名/注释
    【12月DW打卡】joyful-pandas
    【12月DW打卡】joyful-pandas
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5818008.html
Copyright © 2020-2023  润新知