Link
https://jzoj.net/senior/#main/show/3506
Description
从前有一个善良的精灵。
一天,一个年轻人B找到她并请他预言他的未来。这个精灵透过他的水晶球看到这个年轻人将要遇见一个非常美丽的公主并要娶她。。精灵在一张纸上画了N个点并用一些线段将他们连起来,每条线段两端连着不同的点。画完了之后,精灵让年轻人去除一条线段。然后精灵尝试将每个点用红色或者蓝色进行染色,同时使得那里没有一条线段的两端是相同的颜色。如果精灵能够成功染色,这个预言就能成真。
年轻人想要遇见那位公主,因此他请求你去帮助他,找到所有的删除之后能对图进行成功染色的线段。
Solution
0~99分
显然爆搜。
100分
题目大意就是“给你一个无向图,让你删去一条边,使得原图无奇环”
既然考虑到环的奇偶性,自然就得考虑到其个数。按照惯例,绘制一个深度优先生成树(DFS树)
怎么绘制呢?
选择一个点为根,按照DFS的顺序,连出一棵树。当一个点连向一个深度小与它的点,显然,就构成了一个环。
我们称这条边为返祖边,这个环的大小就是两点深度差+1。
然后在树上弄一个类似差分约束的思路,来求出当前边被多少个奇数,偶数环所包括。
对于一条边
(1)全图无环或者只有一个偶环,当前边可以删
(2)如果不符合(1),可以删当前边,仅当当前边被这个图所有奇数环覆盖,且不被一个偶数环包括。
引理1易证
引理2:如果奇数和偶数环在一起,删完后一定不满足。如果不包括所有奇数环,那么在不被当前边包括的奇数环就不满足。
Code
{$inline on} var n,m,i,x,y,tot,tot1,papa:longint; w:array[0..10000] of longint; dis:array[0..10000] of boolean; data:array[0..1000] of longint; pre,tov,last:array[0..20000] of longint; pre1,tov1,cos1,last1:array[0..10000] of longint; ji,ou,numj,numo:array[0..10000] of longint; procedure insert(x,y:longint); inline; begin inc(tot); tov[tot]:=y; pre[tot]:=last[x]; last[x]:=tot; end; procedure insert1(x,y,z:longint); inline; begin inc(tot1); tov1[tot1]:=y; cos1[tot1]:=z; pre1[tot1]:=last1[x]; last1[x]:=tot1; end; procedure dg(x,q,shen:longint); inline; var k:longint; begin dis[x]:=true; w[x]:=shen; k:=last[x]; while k<>0 do begin if tov[k]<>q then begin if not dis[tov[k]] then begin insert1(x,tov[k],(k+1) shr 1); dg(tov[k],x,shen+1); end else if w[tov[k]]<w[x] then begin if odd(w[tov[k]]-w[x]+1) then begin inc(ji[x]); dec(ji[tov[k]]); numj[(k+1) shr 1]:=1; inc(papa); end else begin inc(ou[x]); dec(ou[tov[k]]); numo[(k+1) shr 1]:=1; end; end; end; k:=pre[k]; end; end; procedure find(x:longint); inline; var k:longint; begin k:=last1[x]; while k<>0 do begin find(tov1[k]); numj[cos1[k]]:=ji[tov1[k]]; numo[cos1[k]]:=ou[tov1[k]]; inc(ji[x],numj[cos1[k]]); inc(ou[x],numo[cos1[k]]); k:=pre1[k]; end; end; begin assign(input,‘fairy.in‘);reset(input); assign(output,‘fairy.out‘);rewrite(output); readln(n,m); for i:=1 to m do begin readln(x,y); insert(x,y); insert(y,x); end; for i:=1 to n do if not dis[i] then begin dg(i,0,1); find(i); end; for i:=1 to m do if ((numj[i]=papa) and (numo[i]=0)) or (papa=0) then begin inc(data[0]); data[data[0]]:=i; end; writeln(data[0]); for i:=1 to data[0] do write(data[i],‘ ‘); end.
时间: 2024-11-14 13:27:35