素材采集
【Description】
拿着照相机在幻想乡上空拍摄取材是射命丸文的日常工作。由于没有定期给灵梦提供魔理沙的照片,她被规定只能沿一定的空路飞行。为了方便管理,幻想乡的空路是这样建立的:一开始有三个景点,它们之间互相由空路相连。之后景点被一个一个加入,每个景点都恰好跟已加入的并且有空路相连的两个景点相连。她可以从任何一个景点开始,沿着空路飞行,并且每到一个景点都拍下此处少女的私密照片,最后还要回到一开始的景点。由于拍照太多会引起少女公愤从而被间隙,除了开始的景点要经过两次之外每个景点最多只能经过一次。文文想知道最多能在多少景点取材。
【Input format】
第一行一个数n,代表景点个数。一开始的景点编号为1,2,3,接下来景点的编号按加入的时间顺序依次递增。
接下来n-3行,第i行有两个整数代表第i+3号景点所连接的两个景点编号。
【Output format】
一个数,最多的景点个数。
【Sample input】
5
1 2
2 1
【Sample output】
4
【Range&Others】
20%的数据满足:4≤n≤10。
30%的数据满足:4≤n≤15。
50%的数据满足:4≤n≤1000。
100%的数据满足:4≤n≤100000。
题目应该很好理解吧=w=
暴力dfs,30分
<span style="font-size:14px;">var
n,l,a,b,ans :longint;
i :longint;
last :array[0..100010] of longint;
t :array[0..100010] of longint;
vis :array[0..100010] of boolean;
pre,other :array[0..200010] of longint;
procedure connect(x,y:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
end;
procedure dfs(x:longint);
var
p,q:longint;
begin
q:=last[x];
vis[x]:=true;
while (q<>0) do
begin
p:=other[q];
if not vis[p] then
begin
t[p]:=t[x]+1;
dfs(p);
end else if t[x]-t[p]+1>ans then ans:=t[x]-t[p]+1;
q:=pre[q];
end;
vis[x]:=false;
end;
begin
assign(input,'aya.in');reset(input);
assign(output,'aya.out');rewrite(output);
read(n);
connect(1,2);
connect(2,1);
connect(1,3);
connect(3,1);
connect(2,3);
connect(3,2);
for i:=4 to n do
begin
read(a,b);
connect(i,a);
connect(i,b);
connect(a,i);
connect(b,i);
end;
t[1]:=1;
dfs(1);
writeln(ans);
<strong> close(input);close(output);
end.
</strong></span>
好,下面我们切入正题——满分是怎么来的 0.0
(五体投地的膜拜r神 ,orz,orz,orz )
正解给的是树型DP,但这里是贪心做法(其实原理是一样一样的=。=)
咱们用a[i,1] 和 a[i,2] 来表示第i个点连接的两个点,且保证 a[i,1]<a[i,2]
然后咱们要考虑怎样去记数了=w=
用bb[1,2] 表示1、2 两点左右两边满足题目要求的点数和(不包括1 、2 两个点本身)
同理,bb[2,3] 和 bb[1,3]
(数组bb中不包括1 、2 、3中任意一点)
那么其他点如何表示呢?
用b[i,1] 表示第i个点与 a[i,1] 两点左右点数和(不包括i 和 a[i,1]); b[i,2] 同理=w=
(看不懂含义?没关系下面有多种解释方法,选择一个觉得像正常人说得话的就好了orz)
(关于它的含义,有一下几种表达方法,选一个能看懂的理解一下,意思都是一样的,请包容我一个作文从来不怎么好的渣渣orz
1、表示两点之间连的这条边满足要求的的左右两边点数和(除去两点本身);
2、表示同时过两点的满足要求的最多景点数(不包括两点本身)
3、表示两点在满足要求前提下所能串起的最多景点数(不包括两点本身)
)
注意,数组bb中不包括1、2、3中任意点)
例如下图(不堪入目),bb[2,3]=1;
好,数组的含义理解了,这仅仅是预热,接下来我们就该开始思考,
什么样的情况是满足要求的呢?这些数组又该如何更新呢=w=
首先,由于我们的b数组和bb 数组中并没有包括两点本身,所以每形成一个三满足题意的三元环我们的ans更新分为3部分:
我们以点1 、 2 、3 为例,
对它的更新,需要三条边(红色圈出)的bb数组 以及 三个点本身
所以:
ans=max(ans,bb[1,2]+bb[2,3]+bb[1,3]+3)
如果是点4呢?
即i=4 时
Ans=max(ans.,bb[a[i,1],a[i,2]]+bb[i,1]+bb[i,2]+3) (原本的a[i,1]、a[i,2] 之间的+两条边)
那么,再一般一点的情况,a[i,1] 和 a[i,2] 不是 [1,3]的数呢?
唯二的区别在于bb数组变成了b数组并且并不是b[a[i,1],a[i,2]] 而是不同情况的不同边,
具体见下面的具体分析
Ok,开始分类讨论=w=
一、a[i,2]<=3
由于我们已经保证了a[i,1]<a[i,2] ,所以当a[i,2]<=3 时,显然点i连接的两个点本来就已经形成三元环的1 、 2 、 3 中的两点,
就如上面那幅不堪入目的图一样,4号点的插入就是这种情况,ans的更新如上:
Ans=max(ans.,bb[a[i,1],a[i,2]]+bb[i,1]+bb[i,2]+3)
同时,我们会发现bb[a[i,1],a[i,2] 的数值也发生了相应变化(对应区域范围内多了两条边和一个点,同时那两条边的b也满足了此时的bb[a[i,1],a[i,2]):
bb[a[i,1],a[i,2]=max(bb[a[i,1],a[i,2],b[i,1]+b[i,2]+1);
此时,1/3已经完成了=w=
二、a[i,2]>4
此时稍微复杂了一点,正如上面所提:另一边不再是 b[a[i,1],a[i,2] 而是不同情况的不同边
(1)a[a[i,2],1]=a[i,1]
好吧,翻译成一般语言就是 i所连的大的那个点所连的小节点 与 i所连的小节点 是同一个点,此时会出现下图(保护好眼睛)的情况(用1表示a[i,1],2表示a[i,2] ,空白点为a[a[i,2],2]
:
此时,我们发现,形成三元环的点是 i 、a[i,1] 、 a[i,2],
边是 b[i,1] 、b[i,2] 、b[a[i,2],1]
所以
Ans=max(ans,b[a[i,2],1]+b[i,1]+b[i,2]+3)
同时 :b[a[i,2],1]=max(b[a[i,2],1],b[i,1]+b[i,2]+1)
好,2/3的工作完成了,胜利就在前方=w=
(2)a[a[i,2],1]<>a[i,1](不等于)
那么此时我们还剩下两种小情况:
a[a[i,2],2]=a[i,1]
于是还是上面那个图,空白点含义编程 a[a[i,2],1]
此时,我们发现,形成三元环的点是 i 、a[i,1] 、 a[i,2],
边是 b[i,1] 、b[i,2] 、b[a[i,2],2]
所以
Ans=max(ans,b[a[i,2],2]+b[i,1]+b[i,2]+3)
同时 :b[a[i,2],2]=max(b[a[i,2],2],b[i,1]+b[i,2]+1)
‚完全不同
于是就会形成一种尴尬的局面:
但是,我们根据连接的先后顺序可知,a[a[i,2],2]到最后一定会与a[i,1]相连,
即等效成
于是形成了上面a[a[i,2],2]=a[i,1] 的情况,于是我们便 合二为一 即可
OK,恭喜你99%都已经大功告成了,得意的敲上代码0.0
记住,这时的得意便是日后的后悔,你会发现有wa,还不止一个=。=
为什么?
这时你就要考虑一下你最终输出的结果是什么,我们的ans存的是4~n的最优解,我们还有点 1 、2 、 3 呢=。=
但是,有的同学就会说,没错,我输出的就是bb[1,2]+bb[1,3]+bb[2,3]+3 ,依旧没有AC
那必是啊=。=
当你只输出ans的时候,没有考虑1 、 2、 3,;
当你只输出bb[1,2]+bb[1,3]+bb[2,3]+3 你又没有考虑到其他点的最优解(局部最优解)
怪我喽=。=
所以输出 max(ans,bb[1,2]+bb[1,3]+bb[2,3]+3)
var
n,ans,l,r :longint;
i :longint;
a :array[0..100010,0..3] of longint;
b :array[0..100010,0..3] of longint;
bb :array[0..3,0..3] of longint;
function max(a,b:longint):longint;
begin
if a<b then exit(b) else exit(a);
end;
procedure swap(var a,b:longint);
var
c:longint;
begin
c:=a;a:=b;b:=c;
end;
begin
assign(input,'aya.in');reset(input);
assign(output,'aya.out');rewrite(output);
read(n);
for i:=4 to n do
begin
read(a[i,1],a[i,2]);
if (a[i,1]>a[i,2]) then swap(a[i,1],a[i,2]);
end;
//
for i:=n downto 4 do
begin
l:=a[i,1];
r:=a[i,2];
if (r<=3) then
begin
ans:=max(ans,bb[l,r]+b[i,1]+b[i,2]+3);
bb[l,r]:=max(bb[l,r],b[i,1]+b[i,2]+1);
end else
begin
if (l=a[r,1]) then
begin
ans:=max(ans,b[r,1]+b[i,1]+b[i,2]+3);
b[r,1]:=max(b[r,1],b[i,1]+b[i,2]+1);
end else
begin
ans:=max(ans,b[r,2]+b[i,1]+b[i,2]+3);
b[r,2]:=max(b[r,2],b[i,1]+b[i,2]+1);
end;
end;
end;
//
writeln(max(ans,bb[1,2]+bb[2,3]+bb[1,3]+3));
close(input);close(output);
end.
AC=w=
数据请见 https://www.jianguoyun.com/p/DTuwgroQsq2OBhiakR4 里的aya即为本题
——by Eirlys
转载请注明出处=w=