[BZOJ1040] [ZJOI2008]骑士 解题报告
Description
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
调了很久的样子..首先分析这道题的隐藏条件
虽然看起来这张图杂乱无章,但想对于一个有n个骑士的联通块,必定有n条边,也就是说一定是一个存在且仅存在一个环的图
据说叫做内向树
由于只存在一个环,做法很简单,只需要将环上任意两个点之间的边断开,然后做两次树形DP
当控制v不取的时候,u可取可不取。当控制v取的时候,u一定不能取。
这样大体的思路就构建起来了。具体实现的时候要注意的地方很多。
首先我是用tarjan找的环,与传统的tarjan不同,这里我们要忽略单点,而且要同时保存两个环上的节点
找到了之后把边断开的操作可以在树形DP的时候特判一下
但是发现WA了之后手造了一组数据就发现tarjan出了问题
不管怎样的图好像都成了一个环
突然发现tarjan是应用于有向图的...而这道题的边恰好是无向边
是不是tarjan就不可以用了呢?实际上不会,因为每个节点最多只出去一条边
所以对于环上的任意一个节点只需要保存它到它讨厌的那个骑士的边就可以了
读入数据的时候我就既造了有向边又造了无向边
还是WA,后来手造一组数据又发现了问题...
有一个特殊情况就是可能环的size=2,这个时候实际上和树没什么区别
如果把边断开很可能造成的后果就是其中一个点连出去的点都无法到达了
而当size>2的时候每个点都会与两个点相连,断了左边的路右边还是可以到的
所以当环大小为2的时候需要特判,我直接将v赋为0就解决了这个问题~
还是一道非常锻炼思维和代码能力的题啊。
最近的状态比较好,有耐心一点一点敲代码,一点一点改
果然最后还是AC了呢ww
(好像这道题的题解代码都不长...
1 program bzoj1040; 2 const maxn=1000010;INF=1000000000001; 3 var n,time,top,flag,u,v,ans,head,tail,size:int64; 4 i,j,j1:longint; 5 a,w,fx:array[-1..maxn]of int64; 6 ins,vis,used:array[-1..maxn]of boolean; 7 low,dfn,link,link1,stack,opt:array[-1..maxn]of int64; 8 fa,next,fa1,next1:array[-1..2*maxn]of int64; 9 f:array[-1..maxn,0..1]of int64; 10 11 function min(a,b:int64):int64; 12 begin 13 if a<b then exit(a) else exit(b); 14 end; 15 16 function max(a,b:int64):int64; 17 begin 18 if a>b then exit(a) else exit(b); 19 end; 20 21 procedure tarjan(p:int64); 22 var j:longint; 23 begin 24 used[p]:=false; 25 inc(top);stack[top]:=p;ins[p]:=true; 26 inc(time);dfn[p]:=time;low[p]:=time; 27 j:=link1[p]; 28 while j<>0 do 29 begin 30 if used[fa1[j]] then 31 begin 32 tarjan(fa1[j]); 33 low[p]:=min(low[p],low[fa1[j]]); 34 end else if ins[fa1[j]] then low[p]:=min(low[p],dfn[fa1[j]]); 35 j:=next1[j]; 36 end; 37 if low[p]=dfn[p] then 38 begin 39 if stack[top]=p then 40 begin 41 ins[p]:=false;dec(top); 42 end else 43 begin 44 v:=stack[top];size:=1; 45 ins[v]:=false; 46 repeat 47 dec(top); 48 u:=v;v:=stack[top]; 49 ins[v]:=false; 50 inc(size); 51 until stack[top] = p; 52 dec(top); 53 end; 54 end; 55 end; 56 57 procedure dfs0(p:int64); 58 var j:longint; 59 begin 60 vis[p]:=false; 61 j:=link[p];f[p,0]:=0; 62 while j<>0 do 63 begin 64 if ((p=u)and(fa[j]=v))or((p=v)and(fa[j]=u)) then 65 begin 66 j:=next[j];continue; 67 end; 68 if vis[fa[j]] then 69 begin 70 dfs0(fa[j]); 71 inc(f[p,0],max(f[fa[j],0],f[fa[j],1])); 72 inc(f[p,1],f[fa[j],0]); 73 end; 74 j:=next[j]; 75 end; 76 if p=v then f[p,1]:=-INF else inc(f[p,1],w[p]); 77 end; 78 79 procedure dfs1(p:int64); 80 var j:longint; 81 begin 82 vis[p]:=false; 83 j:=link[p];f[p,0]:=0;f[p,1]:=0; 84 while j<>0 do 85 begin 86 if ((p=u)and(fa[j]=v))or((p=v)and(fa[j]=u)) then 87 begin 88 j:=next[j];continue; 89 end; 90 if vis[fa[j]] then 91 begin 92 dfs1(fa[j]); 93 inc(f[p,0],max(f[fa[j],0],f[fa[j],1])); 94 inc(f[p,1],f[fa[j],0]); 95 end; 96 j:=next[j]; 97 end; 98 if p=v then f[p,0]:=-INF; 99 inc(f[p,1],w[p]); 100 end; 101 102 procedure solve; 103 var tem:int64; 104 begin 105 fillchar(vis,sizeof(vis),true); 106 dfs0(u); 107 tem:=max(f[u,0],f[u,1]); 108 fillchar(vis,sizeof(vis),true); 109 dfs1(u); 110 tem:=max(f[u,0],tem); 111 inc(ans,tem); 112 end; 113 114 procedure add(x,y:int64); 115 begin 116 inc(j);fa[j]:=y;next[j]:=link[x];link[x]:=j; 117 inc(j);fa[j]:=x;next[j]:=link[y];link[y]:=j; 118 inc(j1);fa1[j1]:=y;next1[j1]:=link1[x];link1[x]:=j1; 119 end; 120 121 procedure bfs(p:longint); 122 var j:longint; 123 begin 124 head:=0;tail:=1;opt[1]:=p;fx[p]:=flag; 125 while head<>tail do 126 begin 127 inc(head); 128 j:=link[opt[head]]; 129 while j<>0 do 130 begin 131 if fx[fa[j]]<>flag then 132 begin 133 fx[fa[j]]:=flag; 134 inc(tail);opt[tail]:=fa[j]; 135 end; 136 j:=next[j]; 137 end; 138 end; 139 end; 140 141 begin 142 readln(n); 143 j:=0;j1:=0; 144 for i:=1 to n do 145 begin 146 readln(w[i],a[i]); 147 add(i,a[i]); 148 end; 149 ans:=0; 150 fillchar(fx,sizeof(fx),0); 151 fillchar(used,sizeof(used),true); 152 fillchar(ins,sizeof(ins),false); 153 flag:=0;time:=0;top:=0; 154 for i:=1 to n do if fx[i]=0 then 155 begin 156 inc(flag); 157 bfs(i); 158 u:=0;v:=0; 159 for j:=1 to tail do if used[opt[j]] then tarjan(opt[j]); 160 if size=2 then v:=0; 161 solve; 162 end; 163 writeln(ans); 164 end.