求原图和补图的三元环个数
2.1 题目描述
给定一个无自环重边的无向图,求这个图的三元环1
的个数以及补图2的三元环个数。
2.2 输入格式
第一行 2 个数n,m ,分别表示图的点数、边数。
接下来 m行,每行两个数 u, v ,表示一条连接u, v 的无向边。
2.3 输出格式
一行两个数,依次表示原图的三元环个数以及补图的三元环的个数。
2.4 样例输入
5 5
1 2
1 3
2 3
2 4
3 4
2.5 样例输出
2 1
2.6 数据范围
对于 30%的数据:n ≤ 100
对于 60%的数据:m ≤ 500
对于 100%的数据:n ≤ 105
,m ≤ 105
2.7 评分方式
如果你两个数均输出正确,得 10分。
否则如果两个数中任意一个正确或者两个数的和正确,得 6 分。
否则不得分。
1大小为 3的环。即一个无序三元组 (x, y, z) 使得任意两点之间都有边
2一条连接(u, v)(u = v) 的边,如果在原图中出现了,那么在补图中不会出现,否则一定会在补图中出现。
直接求两个图的三元环个数并不好求,那么如果我们知道了原图和补图三元环个数的和,则只要求其中一种就行了。
但是直接求和也不好求,这时我们可以求那些既不存在于原图也不存在于补图的三元环个数。
可知这些三元环一定是至少有一条边在原图,至少有一条边在补图的,于是它们在两图中都是残缺的。
那么我们记录一下每个点在原图中的度d[i],d[i]*(n-1-d[i])就是经过i点的不在原图也不在补图的三元环个数。(一条边在原图一条边不在,n-1-d[i]为i在补图中的度)
由于我们对每个点都进行了计算,所以算出来的值是两倍的,需要除以2。
全图中三元环个数为,用它减去我们算出来的值就得出了原图和补图三元环个数之和。
现在我们开始统计原图中三元环个数。直接暴力枚举有共点的两条边,然后查找另外两个点有木有边。
我是用的小PO的先把边按照双关键字排序然后二分查找的方法。由于记的是单向边所以不用除以2
1 program Neayo; 2 const 3 inf='triangle.in'; 4 ouf='triangle.out'; 5 var 6 i,j,k,m,n,e:longint; 7 sum,ans:int64; 8 d,s,t,l,r:array[0..100001]of longint; 9 10 function c(x:int64):int64; 11 begin 12 c:=(x*(x-1)*int64(x-2)) div 6; 13 end; 14 procedure qsort(l,r:longint); 15 var x,x1,x2,i,j:longint; 16 begin 17 i:=l;j:=r; 18 x1:=s[(l+r)shr 1]; 19 x2:=t[(l+r)shr 1]; 20 repeat 21 while (s[i]<x1)or((s[i]=x1)and(t[i]<x2))do inc(i); 22 while (s[j]>x1)or((s[j]=x1)and(t[j]>x2))do dec(j); 23 if i<=j then 24 begin 25 x:=s[i];s[i]:=s[j];s[j]:=x; 26 x:=t[i];t[i]:=t[j];t[j]:=x; 27 inc(i); 28 dec(j); 29 end; 30 until(i>j); 31 if i<r then qsort(i,r); 32 if j>l then qsort(l,j); 33 end; 34 procedure init; 35 var x,y,tmp:int64; 36 begin 37 assign(input,inf);assign(output,ouf); 38 reset(input);rewrite(output); 39 readln(n,m); 40 for i:=1 to m do 41 begin 42 readln(x,y); 43 if x>y then begin tmp:=x;x:=y;y:=tmp;end; 44 s[i]:=x;t[i]:=y; 45 inc(d[x]); 46 inc(d[y]); 47 end; 48 sum:=0; 49 for i:=1 to n do 50 sum:=sum+d[i]*(n-1-d[i]); 51 sum:=sum div 2; 52 sum:=c(n)-sum; 53 close(input); 54 end; 55 //================= 56 function find(x,l,r:longint):boolean; 57 var mid:longint; 58 begin 59 60 while l<=r do 61 begin 62 mid:=(l+r)shr 1; 63 if (t[mid]>x)then r:=mid-1 64 else if (t[mid]=x) then exit(true) 65 else l:=mid+1; 66 end; 67 exit(false); 68 end; 69 procedure go; 70 var 71 t1,t2:int64; 72 have:boolean; 73 begin 74 qsort(1,m); 75 for i:=1 to m+1 do 76 if s[i]<>s[i-1]then 77 begin 78 r[s[i-1]]:=i-1; 79 l[s[i]]:=i; 80 r[s[i]]:=i; 81 end; 82 for k:=1 to n do 83 begin 84 for i:=l[k] to r[k]-1 do 85 begin 86 t1:=t[i]; 87 for j:=i+1 to r[k] do 88 begin 89 t2:=t[j]; 90 if find(t2,l[t1],r[t1]) then inc(ans); 91 end; 92 end; 93 end; 94 writeln(ans,' ',sum-ans); 95 end; 96 begin 97 init; 98 go; 99 close(output); 100 end.