原题链接
题意:
每个骑士有一个不可以同时上场的骑士,和一个战斗力。求最大战斗力。
思路:
类似没有上司的舞会。
这个题构成的是基环树森林,取每个基环树的最大值累加就是答案。
把每个基环树环上的一条边断开后,就构成了一棵树,这时候就相当于是没有上司的舞会那道题了。存图的时候默认的关系是两个人不能同时选择,也就需要分别强制选一个不选另一个,来跑两次DP,取max.
存图的时候存有向边,边的指向两种都可以。
注意答案会爆int。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll>PLL; typedef pair<int,int>PII; typedef pair<double,double>PDD; #define I_int ll inline ll read() { ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } char F[200]; inline void out(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); //cout<<" "; } ll ksm(ll a,ll b,ll p) { ll res=1; while(b) { if(b&1)res=res*a%p; a=a*a%p; b>>=1; } return res; } const int inf=0x3f3f3f3f,mod=998244353; const ll INF = 0x3f3f3f3f3f3f3f3f; const double PI = atan(1.0)*4; const int maxn=1e6+100; int n,w[maxn],fa[maxn]; bool vis[maxn]; ll res; int h[maxn],idx; struct node{ int e,ne; }edge[maxn*2]; ll dp[maxn][2]; void add(int u,int v){ edge[idx]={v,h[u]};h[u]=idx++; } void DP(int u,int root){ vis[u]=1; dp[u][0]=0;dp[u][1]=w[u]; for(int i=h[u];~i;i=edge[i].ne){ int j=edge[i].e; if(j!=root){ DP(j,root); dp[u][0]+=max(dp[j][0],dp[j][1]); dp[u][1]+=dp[j][0]; } else dp[j][1]=-inf; } } void dfs(int u){ vis[u]=1; int root=u; while(!vis[fa[root]]){ root=fa[root];vis[root]=1; } DP(root,root); ll tmp=max(dp[root][0],dp[root][1]); vis[root]=1;root=fa[root]; DP(root,root); tmp=max(tmp,max(dp[root][0],dp[root][1])); res+=tmp; } int main(){ memset(h,-1,sizeof h); n=read(); for(int i=1;i<=n;i++){ w[i]=read();///该骑士的战斗力 int x=read();///i讨厌x add(x,i); fa[i]=x; } for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);///对每个没访问的点dfs printf("%lld\n",res); return 0; }