Luogu P2607 骑士
题意#
每个骑士有且只有一个讨厌的人,即他们两个不能同时出现在一个队伍之中.
每个骑士都有一个攻击力.求凑齐一个团队攻击力最大是多少.
分析#
因为每个骑士只有一个讨厌的人,所以可以建一个外向树(即每个节点只有一个父节点).
由于是 个点条边,因此一定存在环,我们只需要断一条环上的边,就可以得到一棵树
得到树之后,我们就可以愉快的进行树形DP了 (▽)
如何破环?#
我们首先需要找到环上的一个点,那么他和他的父节点所连边一定为环上一条边,我们考虑把它断开
首先我们知道,无论此边是否断开,这两个点是都不可以同时选的。
所以我们可以假设这条边被断开,分别以这条边的两个断点为根进行树形DP取最大值即可
AC_CODE#
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define leng(a) (int)a.size()
#define lowbit(x) (x&-x)
#define fix(a) fixed << setprecision(a)
#define debug(x) cout<<#x" ----> "<<x<<endl
#define rep(i, b, s) for(int i = (b); i <= (s); ++i)
#define pre(i, b, s) for(int i = (b); i >= (s); --i)
#define TEST int T; read(T); while(T --)
//#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
#define all(v) (v).begin(),(v).end()
using namespace std;
typedef unsigned long long ULL;
typedef pair<int, int> PII ;
typedef pair<int, PII> PIII ;// {value, {value, value}}
typedef pair<double, double> PDD ;
typedef long long LL;
const int INF = INT_MAX;
const LL INFF = INT64_MAX;
const int MOD = 998244353;
const double eps = 1e-10;
const double pi = acos(-1.0);
LL gcd(LL a, LL b) {return b ? gcd(b, a%b) : a;}
inline LL ksm(LL a, LL b) {if (b == 0) return 1; LL ns = ksm(a, b >> 1); ns = ns * ns % MOD; if (b & 1) ns = ns * a % MOD; return ns;}
inline LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
inline void out(bool flag);
template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
template <typename T> inline T mod(T &x) {return x % MOD;}
template < typename T >
inline void read(T &x)
{
x = 0; bool f = 0; char ch = getchar();
while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
x = f ? -x : x;
}
// __builtin_popcount(x) 返回x中1的个数
// __lg(x) 返回x的二进制下的位数(去除前导零实现,特判0)
//map<key,value>; key 可以是PII
//再用unordered_map 是sb
const int N = 1e6 + 10;
int h[N], e[N], ne[N], idx;
int w[N], fa[N];
int n, mark;
bool vis[N];
LL ans, res, RES;
LL f[N][2];
//加边
inline void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
//树形DP mark为标记过的环的端点
void dfs(int u) {
f[u][1] = w[u], f[u][0] = 0;
vis[u] = true;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j != mark) {
dfs(j);
f[u][0] += max(f[j][0], f[j][1]);
f[u][1] += f[j][0];
} else f[j][1] = -INFF;
}
}
//找环上的点 因为是外向树,每个点只有一个父节点
//我们一直对某个点寻找父节点 一定可以找到环上的点
void get_circle(int u) {
vis[u] = true;
while(!vis[fa[u]]) {
u = fa[u];
vis[u] = true;
}
res = 0;
mark = u;
dfs(mark);
res = max(f[u][0], f[u][1]);
mark = fa[mark];
vis[mark] = true;
dfs(mark);
ans += max(max(f[mark][0], f[mark][1]), res);
}
inline void solve() {
read(n);
rep(i, 1, n) h[i] = -1;
rep(i, 1, n) {
read(w[i]);
read(fa[i]);
add(fa[i], i);
// cout << w[i] << endl;
}
rep(i, 1, n)
if(!vis[i])
get_circle(i);
printf("%lld\n", ans);
}
signed main()
{
solve();
return 0;
}
inline void out(bool flag) {
if(flag) puts("YES");
else puts("NO");
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现