标签:
bzoj1040 骑士
题目大意:给出每个骑士的攻击力和痛恨的人,每个骑士不能和自己痛恨的人一起出现,选一些骑士使得他们的攻击力最大。
思路:因为每个骑士恨一个人,所以是一个环套树森林(注意n点n边的联通图可能是环套树森林!!!),虽然题目是单向边,但等同于双向边。对于环套树dp的做法,可以搜到环后,把环从一处断开,对于这道题目,对断开后的两点分别为根做树型dp(要求根不能选),加给答案。但是要注意二元环的情况,我们可以对于二元环只加一次无向边(其实是两条有向边),因为二元环完全可以当作有边相连的两点处理,这个时候可能会出现一棵没有环的树,我们需要在退回到dfs起点的那个点的时候人为的做一下dp。
一定要十分注意二元环的情况!!!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define maxnode 1000005 using namespace std; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},tot=0,x=0,y=0,ai[maxnode]={0}; LL val[maxnode]={0},f[maxnode][2]={0},ans=0; bool visit[maxnode]={false},ff; void add(int u,int v) { ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v; ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void dp(int u,int fa) { int i,j; f[u][1]=val[u];visit[u]=true; for (i=point[u];i;i=next[i]) { if (en[i]!=fa) { if ((u==y&&en[i]==x)||(u==x&&en[i]==y)) continue; dp(en[i],u); f[u][0]+=max(f[en[i]][0],f[en[i]][1]); f[u][1]+=f[en[i]][0]; } } } void dfs(int u,int fa) { int i,j;LL ci=0; visit[u]=true; for (i=point[u];i;i=next[i]) { if (en[i]!=fa) { if (visit[en[i]]) { x=u;y=en[i]; memset(f,0,sizeof(f)); dp(x,y);ci=max(ci,f[x][0]); memset(f,0,sizeof(f)); swap(x,y);dp(x,y);ci=max(ci,f[x][0]); ans+=ci;ff=true;return; } else { dfs(en[i],u);if (ff) return; } } } if (fa==0) { x=y=0;dp(u,0); ans+=max(f[u][0],f[u][1]); } } int main() { int n,i,j; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%I64d%d",&val[i],&ai[i]); for (i=1;i<=n;++i) if (ai[ai[i]]!=i||ai[i]>i) add(i,ai[i]); for (i=1;i<=n;++i) if (!visit[i]){ff=false;dfs(i,0);} printf("%I64d\n",ans); }
标签:
原文地址:http://www.cnblogs.com/Rivendell/p/4760952.html