zoukankan      html  css  js  c++  java
  • BZOJ 1040 骑士 基环树 树形DP

    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=1040

    题目大意:

    Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一 些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战 斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。 

    思路:

    基环树:

    求基环树森林的最大权独立集。

    分解成多个基环树求解即可,对于每个基环树,只有一个环,任意去掉环上的一条边u,v,以u为根节点跑一遍DP,记录u不取的ans1,再以v为根节点跑一遍DP,记录v不取的ans2,这个基环树的最大权独立集就是max(ans1, ans2)

    找出环上的一条边可以用并查集来做。

     1 #include<bits/stdc++.h>
     2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
     3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
     4 #define Min(a, b) ((a) < (b) ? (a) : (b))
     5 #define Mem(a) memset(a, 0, sizeof(a))
     6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
     7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
     8 #define lson ((o)<<1)
     9 #define rson ((o)<<1|1)
    10 #define Accepted 0
    11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
    12 using namespace std;
    13 inline int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    18     return x*f;
    19 }
    20 
    21 typedef long long ll;
    22 const int maxn = 1000000 + 10;
    23 const int MOD = 1000000007;//const引用更快,宏定义也更快
    24 const int INF = 1e9 + 7;
    25 const double eps = 1e-6;
    26 
    27 ll dp[maxn][2];
    28 ll a[maxn];
    29 int p[maxn];
    30 vector<int>G[maxn];
    31 
    32 int Find(int x)
    33 {
    34     return x == p[x] ? x : p[x] = Find(p[x]);
    35 }
    36 void dfs(int u, int fa)
    37 {
    38     dp[u][0] = 0;
    39     dp[u][1] = a[u];
    40     for(int i = 0; i < G[u].size(); i++)
    41     {
    42         int v = G[u][i];
    43         if(v == fa)continue;
    44         dfs(v, u);
    45         dp[u][0] += max(dp[v][0], dp[v][1]);
    46         dp[u][1] += dp[v][0];
    47     }
    48     //cout<<u<<" "<<dp[u][0]<<" "<<dp[u][1]<<endl;
    49 }
    50 int u[maxn], v[maxn];
    51 int main()
    52 {
    53     int n, tot = 0;
    54     scanf("%d", &n);
    55     for(int i = 1; i <= n; i++)p[i] = i;
    56     for(int i = 1; i <= n; i++)
    57     {
    58         int x;
    59         scanf("%lld%d", &a[i], &x);
    60         int a = Find(i), b = Find(x);
    61         if(a == b)//基环树的环上的一条边 断开
    62         {
    63             u[tot] = i; //是基环树森林 有多个基环树
    64             v[tot++] = x;
    65         }
    66         else
    67         {
    68             p[a] = b;
    69             G[i].push_back(x);
    70             G[x].push_back(i);
    71         }
    72     }
    73     ll ans = 0, tmp;
    74     for(int i = 0; i < tot; i++)
    75     {
    76         dfs(u[i], -1);
    77         tmp = dp[u[i]][0];//不选u的最大值
    78         dfs(v[i], -1);
    79         tmp = max(tmp, dp[v[i]][0]);//不选v的最大值
    80         ans += tmp;
    81     }
    82     printf("%lld
    ", ans);
    83     return Accepted;
    84 }
  • 相关阅读:
    安装好k8s后,使用kubectl get cs 查看状态,发现 controller-manager scheduler Unhealthy
    k8s 去掉node标签 难去的
    项目中常用到的布局 flex
    scanf输入空格
    sed和awk学习第一天
    线程池
    线程间通信 | 等待唤醒机制
    创建线程的三种方法详细对比
    EXCEL中VLOOKUP函数的使用
    Vulnhub实战靶场:GAARA: 1
  • 原文地址:https://www.cnblogs.com/fzl194/p/9688112.html
Copyright © 2011-2022 走看看