zoukankan      html  css  js  c++  java
  • SOJ 1219. 新红黑树

    解题技巧:

      1.输入的树可能不是根据从根节点到子节点的顺序输入的。

        例如:

          输入可能是:

          3

          1 0 1 100

          2 1 -1 200

          2 3 1 400

       所以一个较笨的方法是:先存成矩阵的形式,再转换成邻接链表的形式。

      2.接着是一个记忆化搜索的过程。因为树枝数n<=20,即节点数<=21,故可以借助位运算的技巧,将一个树的状态压缩成一个整数。

        树的状态是指树中哪些节点是有效可访问的。

        dp[i][j]记录的是树的状态为i时,j先剪树的使得D满足j的期望的最优值.对剪红树枝的A来说,D越大越好;对剪黑树枝的B来说,D越小越好。

      3.注意在计算dp[i][j]时,如果当前j不能剪树枝,则证明状态为i的树中,所有树枝都是另外一种颜色(j不能剪的颜色)。

    代码如下:

      1 #include <cstdio>
      2 #include <vector>
      3 #include <queue>
      4 #include <climits>
      5 #include <algorithm>
      6 using namespace std;
      7 
      8 struct Edge {
      9     int to;
     10     int color;  // color = 0 -> red  | color = 1 -> black
     11     int weight;
     12     Edge(int t = 0, int c = 0, int w = 0) : to(t), color(c), weight(w) {}
     13 };
     14 
     15 struct Attribute {
     16     bool used;
     17     int color;
     18     int weight;
     19 };
     20 
     21 const int maxn = 20;
     22 const int states = 1 << 21;
     23 const int INF = INT_MAX;
     24 Attribute m[maxn + 1][maxn + 1];
     25 
     26 vector<Edge> matrix[maxn + 1];
     27 
     28 bool visited[maxn + 1];
     29 int n;
     30 
     31 int dp[states][2];  // dp[i][j] 表示状态为i的树j先走的D的最大值
     32 int subtree[maxn + 1];  // 子树的状态
     33 
     34 void init() {
     35     for (int i = 0; i < maxn + 1; ++i) {
     36         for (int j = 0; j < maxn + 1; ++j)
     37             m[i][j].used = false;
     38         matrix[i].clear();
     39         visited[i] = false;
     40         subtree[i] = 0;
     41     }
     42     for (int i = 0; i < states; ++i) dp[i][0] = dp[i][1] = INF;
     43     dp[1][0] = dp[1][1] = 0;
     44 }
     45 
     46 void transform(int cur) {
     47     visited[cur] = true;
     48     vector<Edge> &vt = matrix[cur];
     49     for (int i = 0; i <= n; ++i) {
     50         if (!visited[i] && m[cur][i].used) {
     51             vt.push_back(Edge(i, m[cur][i].color, m[cur][i].weight));
     52             transform(i);
     53         }
     54     }
     55 }
     56 
     57 int subTree(int root) {
     58     vector<Edge> &vt = matrix[root];
     59     int state = 1 << root;
     60     for (int i = 0; i < vt.size(); ++i) {
     61         Edge &e = vt[i];
     62         state += subTree(e.to);
     63     }
     64     return subtree[root] = state;
     65 }
     66 
     67 int DP(int state, int color) {
     68     if (dp[state][color] != INF) return dp[state][color];
     69     
     70     if (color == 0) dp[state][color] = -INF;
     71     else dp[state][color] = INF;
     72 
     73     int tot[2] = { 0, 0 };
     74     bool canCut = false;
     75 
     76     queue<int> que;
     77     que.push(0);
     78     while (!que.empty()) {
     79         int cur = que.front(); que.pop();
     80         vector<Edge> &vt = matrix[cur];
     81         for (int i = 0; i < vt.size(); ++i) {
     82             Edge &e = vt[i];
     83             if (((1 << e.to) & state) == 0) continue;
     84             que.push(e.to);
     85             if (e.color == color) {
     86                 canCut = true;  // 表示需要修剪的颜色为color时,可以找到可剪的树枝
     87                 int weight = (color == 0 ? e.weight : -e.weight);
     88                 int st = subtree[e.to]; // 包括e.to
     89                 int next_state = state & (~st);
     90                 int next_color = (color + 1) % 2;
     91                 if (color == 0) {
     92                     dp[state][color] = max(dp[state][color], DP(next_state, next_color) + weight);
     93                 } else {
     94                     dp[state][color] = min(dp[state][color], DP(next_state, next_color) + weight);
     95                 }
     96             }
     97             tot[e.color] += (e.color == 0 ? e.weight : -e.weight);
     98         }
     99     }
    100     if (!canCut) dp[state][color] = tot[(color + 1) % 2];   // 如果全部都是另外一种情况,则另外一种情况必然全选
    101     return dp[state][color];
    102 }
    103 
    104 int main() {
    105     while (scanf("%d", &n) != EOF) {
    106         init();
    107 
    108         // 读入新红黑树
    109         int node1, node2, color, weight;
    110         for (int i = 0; i < n; ++i) {
    111             scanf("%d%d%d%d", &node1, &node2, &color, &weight);
    112             color = color == -1 ? 1 : 0;    // color = 0 -> red | color = 1 -> black
    113             m[node1][node2].used = m[node2][node1].used = true;
    114             m[node1][node2].color = m[node2][node1].color = color;
    115             m[node1][node2].weight = m[node2][node1].weight = weight;
    116         }
    117 
    118         // 转换新红黑树->邻接链表
    119         transform(0);
    120         // 构造每个子树的状态
    121         subTree(0);
    122 
    123         // 使用算法查找红黑树状态为(111...111),A均(砍红树)现行的D的最大值
    124         int state = (1 << (n + 1)) - 1;
    125         printf("%d
    ", DP(state, 0));
    126     }
    127     return 0;
    128 }
  • 相关阅读:
    Angular 一个简单的指令实现 阻止事件扩散
    怎样group by一列 select多列
    Angular Viewchild undefined
    TypeScript扩展类方法
    vmware station-ubuntu18.04 共享剪贴板
    基于R统计软件的三次样条和平滑样条模型数据拟合及预测
    R语言析因设计分析:线性模型中的对比
    R语言逻辑回归、方差分析&#160;、伪R平方分析
    R语言多重比较方法
    R语言逐步多元回归模型分析长鼻鱼密度影响因素
  • 原文地址:https://www.cnblogs.com/mchcylh/p/5115629.html
Copyright © 2011-2022 走看看