求原图和补图的三元环个数

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.

 

 

posted @ 2012-11-04 21:29  neayo  阅读(855)  评论(0编辑  收藏  举报