[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.

 

posted @ 2015-04-10 08:56  mjy0724  阅读(180)  评论(0编辑  收藏  举报