bzoj 1040: [ZJOI2008]骑士
Description
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
Input
第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力
和他最痛恨的骑士。
Output
应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。
Sample Input
10 2
20 3
30 1
Sample Output
HINT
N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。
思路
乍一看,没什么思路,
再一看,一共有n个点,连了m条边,求最大独立集?
基环树裸题啊。(此处是森林)
一棵树,多了一条边使得其产生一个环,就叫基环树。
一般的做法是把环拎出来,
想象着环上每个点下面挂着子树,
然后对子树查询,最后放到环上进行查询。
而这题就更方便了。
假设只有一棵树,定义数组f[100001][2]
f[i][0]表示i这个点不选时的子树最优解
f[i][1]表示i这个点选上时的子树最优解
dp方程非常显然。
再考虑基环树。
只要找出环上任意一条边a-b,
那么a,b中至少有一个不被选中,
我们可以割掉a-b这条边,
然后从a开始树形dp,记f[a][0];从b开始树形dp,记f[b][0],
那么ans+=max(f[a][0],f[b][0])即可
代码
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 #define ref(i,x,y)for(int i=x;i<=y;++i) 5 #define eef(i,x)for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)if(y!=fa) 6 int read() 7 { 8 char c=getchar();int d=0,f=1; 9 for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1; 10 for(;c>='0'&&c<='9';d=d*10+c-48,c=getchar()); 11 return d*f; 12 } 13 typedef long long ll; 14 const int N=1000001; 15 int n,cnt,xx,yy; 16 int head[N],vis[N],w[N],pt[N]; 17 ll f[N][2]; 18 struct xint{int to,next;}e[N*2]; 19 void addedge(int x,int y) 20 { 21 e[++cnt]=(xint){y,head[x]};head[x]=cnt; 22 e[++cnt]=(xint){x,head[y]};head[y]=cnt; 23 } 24 void dfs1(int fa,int x) 25 { 26 vis[x]=1; 27 eef(i,x)if(!vis[y])dfs1(x,y);else xx=x,yy=y; 28 } 29 void dfs2(int fa,int x) 30 { 31 f[x][0]=0; 32 f[x][1]=w[x]; 33 eef(i,x) 34 { 35 if(x==xx&&y==yy||y==xx&&x==yy)continue; 36 dfs2(x,y); 37 f[x][1]+=f[y][0]; 38 f[x][0]+=max(f[y][0],f[y][1]); 39 } 40 } 41 void work() 42 { 43 ll ans=0; 44 ref(i,1,n)if(!vis[i]) 45 { 46 xx=yy=0; 47 dfs1(0,i); 48 ll tmp=0; 49 if(!xx&&!yy) 50 { 51 dfs2(0,i); 52 tmp=max(f[i][1],f[i][0]); 53 } 54 else 55 { 56 dfs2(0,xx); 57 tmp=f[xx][0]; 58 dfs2(0,yy); 59 tmp=max(tmp,f[yy][0]); 60 } 61 ans+=tmp; 62 } 63 cout<<ans<<endl; 64 } 65 int main() 66 { 67 n=read(); 68 ref(i,1,n) 69 { 70 w[i]=read();pt[i]=read(); 71 if(pt[pt[i]]!=i)addedge(i,pt[i]); 72 } 73 work(); 74 }