三元环HDU 6184

HDU - 6184 C - Counting Stars

  题目大意:有n个点,m条边,问有一共有多少个‘structure’也就是满足V=(A,B,C,D) and E=(AB,BC,CD,DA,AC)这样一个图形,类似于四边形中间连接了一条对角线。

  如果我们把这个四边形拆分的话,其实就是两个共用一条边的三角形,而在图中就是三元环。求三元环有两种求法,个人感觉这个三元环的时间复杂度很玄学。

  第一种一种就是枚举点x,然后枚举和点x相连的y,这时根据y的度,如果y的度小于等于sqrt(m),那么我们可以直接枚举和y相连的z,看z和x是否相连,这时时间复杂度最差是m*sqrt(m),如果y的度大于sqrt(m)的话,说明y有很多点相连,再枚举y的话就会超时,这时枚举再枚举x找z,根据set或者map来判断y和z是否相连,复杂度最差也是m*sqrt(m),详情见代码

 1 #include<cstdio>
 2 #include<vector>
 3 #include<set>
 4 #include<cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=100118;
 8 set<ll> s;
 9 vector<int> vv[N];
10 int link[N],book[N];
11 inline void init(int n)
12 {
13     s.clear();
14     for(int i=0;i<=n;i++)
15     {
16         vv[i].clear();
17         link[i]=0;
18         book[i]=0;
19     }
20 }
21 int main()
22 {
23     int n,m,u,v;
24     while(~scanf("%d%d",&n,&m))
25     {
26         init(n);
27         for(int i=0;i<m;i++)
28         {
29             scanf("%d%d",&u,&v);
30             vv[u].push_back(v);
31             vv[v].push_back(u);
32             s.insert(1ll*u*(n+1)+v);//set保存u和v相连的信息
33             s.insert(1ll*v*(n+1)+u);
34         }
35         ll ans=0;
36         for(int x=1;x<=n;x++)
37         {
38             book[x]=1;//每个点只有枚举一遍
39             for(int i=0;i<vv[x].size();i++)
40                 link[vv[x][i]]=x;//记录和x点相连的点
41             //枚举和x相连的y
42             for(int i=0;i<vv[x].size();i++)
43             {
44                 int y=vv[x][i],sum=0;
45                 if(book[y])
46                     continue;
47                 if(1ll*vv[y].size()*vv[y].size()<=m)
48                 {
49                     //枚举找到和x相连的z
50                     for(int j=0;j<vv[y].size();j++)
51                         if(link[vv[y][j]]==x)
52                             sum++;
53                 }
54                 else
55                 {
56                     //枚举找到和y相连的z
57                     for(int j=0;j<vv[x].size();j++)
58                         if(s.find(1ll*y*(n+1)+vv[x][j])!=s.end())
59                             sum++;
60                 }
61                 ans+=1ll*sum*(sum-1)/2;//每两个三元环就可以组成一个需要的图形
62             }
63         }
64         printf("%lld\n",ans);
65     }
66     return 0;
67 }

暴力m*sqrt(m)

  当然上面那个做法有点类似于暴力,而且前向星建图会超时,不知道为啥子,所以我们还需要第二种方法

  第二种是枚举边,不过得先对边进行处理。也就是统计每个点的度,然后我们根据这个度把之前的双向边变成度数大的点指向度数小的点,度数相同按序号的有向边,这样构成了一个有向无环图。这样我们枚举每条边,统计这条边能构成几个三元环,最后统计答案。但时间复杂度我不懂算,很玄学,比第一种快了不只一倍,并且在建边时用swap会超时。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 typedef long long ll;
 6 typedef pair<int,int> pii;
 7 const int N=100118;
 8 vector<pii> vv[N];
 9 int link[N],line[N],du[N],val[2*N],u[2*N],v[2*N];
10 inline void init(int n)
11 {
12     for(int i=0;i<=n;i++)
13     {
14         du[i]=0;
15         vv[i].clear();
16         link[i]=line[i]=0;
17     }
18 }
19 int main()
20 {
21     int n,m;
22     while(~scanf("%d%d",&n,&m))
23     {
24         init(n);
25         for(int i=1;i<=m;i++)
26         {
27             val[i]=0;
28             scanf("%d%d",&u[i],&v[i]);
29             du[u[i]]++,du[v[i]]++;
30         }
31         for(int i=1;i<=m;i++)//按度数改成有向边
32         {//每条边记录下另一个端点和边的编号
33             if(du[u[i]]<du[v[i]])
34                 vv[u[i]].push_back(pii(v[i],i));
35             else if(du[u[i]]>du[v[i]])
36                 vv[v[i]].push_back(pii(u[i],i));
37             else
38             {
39                 if(u[i]<v[i])
40                     vv[u[i]].push_back(pii(v[i],i));
41                 else
42                     vv[v[i]].push_back(pii(u[i],i));
43             }
44         //    改成swap(u[i],v[i]),然后再建边会超时
45         }
46         for(int i=1;i<=m;i++)//枚举每条边
47         {
48             int x=u[i],y=v[i];
49             for(int j=0;j<vv[x].size();j++)
50             {//遍历和x相连的z
51                 int z=vv[x][j].first,id=vv[x][j].second;
52                 link[z]=x;//z和x相连
53                 line[z]=id;//记录相连的这条边的编号
54             }
55             for(int j=0;j<vv[y].size();j++)
56             {//遍历和y相连的z
57                 int z=vv[y][j].first,id=vv[y][j].second;
58                 if(link[z]==x)
59                 {//如果这个z和x相连的话
60                     val[i]++;
61                     val[id]++;
62                     val[line[z]]++;
63                     //相关的三条边都可以组成了一个三元环
64                 }
65             }
66         }
67         ll ans=0;
68         for(int i=1;i<=m;i++)
69             ans+=1ll*val[i]*(val[i]-1)/2;
70         printf("%lld\n",ans);
71     }
72     return 0;
73 }

vector建图

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=100118;
 7 struct Side{
 8     int v,ne;
 9 }S[2*N];
10 int sn,head[N],link[N],line[N],du[N],val[2*N],u[2*N],v[2*N];
11 inline void init(int n)
12 {
13     sn=0;
14     for(int i=0;i<=n;i++)
15     {
16         head[i]=-1;
17         du[i]=0;
18         link[i]=0;
19         line[i]=-1;
20     }
21 }
22 inline void add(int u,int v)
23 {
24     S[sn].v=v;
25     S[sn].ne=head[u];
26     head[u]=sn++;
27 }
28 int main()
29 {
30     int n,m;
31     while(~scanf("%d%d",&n,&m))
32     {
33         init(n);
34         for(int i=0;i<m;i++)
35         {
36             val[i]=0;
37             scanf("%d%d",&u[i],&v[i]);
38             du[u[i]]++,du[v[i]]++;
39         }
40         for(int i=0;i<m;i++)
41         {
42             if(du[u[i]]<du[v[i]])
43                 add(u[i],v[i]);
44             else if(du[u[i]]>du[v[i]])
45                 add(v[i],u[i]);
46             else
47             {
48                 if(u[i]<v[i])
49                     add(u[i],v[i]);
50                 else
51                     add(v[i],u[i]);
52             }
53         }
54         for(int i=0;i<m;i++)
55         {
56             int x=u[i],y=v[i];
57             for(int j=head[x];j!=-1;j=S[j].ne)
58             {
59                 link[S[j].v]=x;
60                 line[S[j].v]=j;
61             }
62             for(int j=head[y];j!=-1;j=S[j].ne)
63             {
64                 int z=S[j].v;
65                 if(link[z]==x)
66                 {
67                     val[i]++;
68                     val[j]++;
69                     val[line[z]]++;
70                 }
71             }
72         }
73         ll ans=0;
74         for(int i=0;i<m;i++)
75             ans+=1ll*val[i]*(val[i]-1)/2;
76         printf("%lld\n",ans);
77     }
78     return 0;
79 }

前向星建图

原文地址:https://www.cnblogs.com/LMCC1108/p/10693605.html

时间: 2024-10-29 19:05:41

三元环HDU 6184的相关文章

HDU 6184 Counting Stars 经典三元环计数

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6184 题意: n个点m条边的无向图,问有多少个A-structure 其中A-structure满足V=(A,B,C,D) && E=(AB,BC,CD,DA,AC) 解法: 可以看出A-structure是由两个有公共边的三元环构成的,然后就变成了这道题. http://www.cnblogs.com/spfa/p/7495438.html #include <stdio.h>

Gym - 100342J Triatrip (bitset求三元环个数)

https://vjudge.net/problem/Gym-100342J 题意:给出一个邻接矩阵有向图,求图中的三元环的个数. 思路: 利用bitset暴力求解,记得最后需要/3. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #incl

竞赛图如何构造三元环

讲解视频 一场NOIp模拟赛的T3里看到的一个东西,因为那道题目不开放评测,所以简单写一下. 假设存在这样一张竞赛图,其中存在这样一个环 $node_a \rightarrow node_b \rightarrow node_c \rightarrow node_d \rightarrow node_e \rightarrow node_a$ 首先明确,这是一个竞赛图,对于任意的$node_a$和$node_b$,要么存在$node_a \rightarrow node_b$要么存在$node_

三元环:在数集中求有多少个三元子集中的元素两两互质

2.14在杭二参加集训,校园好美!!!QAQ 杜教在下午为大家做了上午三题的讲解和一些CF杂题的选讲,其中有在图上求所有三元环的算法.这个算法不是很复杂,但还是蛮有趣的啦QWQ 我们已有一些整数,记作a1,a2,...,an.我们希望求出这些数中有多个含有三个元素的子集满足题目的条件,即{ai,aj,ak}中(ai,aj)=1且(ai,ak)=1且(aj,ak)=1. 第一步,建图.将a1,a2,...an分别作为编号为1,2,...,n的点处理,且如果ai和aj互质,那么结点i和结点j之间建立

Codeforces Gym 100342J Problem J. Triatrip 三元环

题目链接: http://codeforces.com/gym/100342 题意: 求三元环的个数 题解: 用bitset分别统计每个点的出度的边和入度的边. 枚举每一条边(a,b),计算以b为出度的边的终点构成的点集和以a为入度的边的起点够成的点集的交集,更新答案. 代码: #include<iostream> #include<cstring> #include<cstdio> #include<bitset> using namespace std;

Codeforces Gym 100342J Problem J. Triatrip 求三元环的数量 bitset

Problem J. Triatrip Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/attachments Description The travel agency “Four Russians” is offering the new service for their clients. Unlike other agencies that only suggest one-way

Gym - 100342J:Triatrip(Bitset加速求三元环的数量)

题意:求有向图里面有多少个三元环. 思路:枚举起点A,遍历A可以到的B,然后求C的数量,C的数量位B可以到是地方X集合,和可以到A的地方Y集合的交集(X&Y). B点可以枚举,也可以遍历.(两种都试过,区别不大.) 枚举代码: #include<cstdio> #include<bitset> #include<cstdlib> #include<cstring> #include<iostream> #include<algori

HDU 6184 Counting Stars

Problem Description Little A is an astronomy lover, and he has found that the sky was so beautiful!So he is counting stars now!There are n stars in the sky, and little A has connected them by m non-directional edges.It is guranteed that no edges conn

黑科技之三元环讲解

三元环是一个不怎么常见的黑科技,它的求解方法是一种基于分块思想的方法,比较简单好写,在这里介绍一下三元环的计数方法及正确性与时间复杂度证明. 对于一个n个点m条边的无向图,三元环是指对于图上的三个点,两两点之间都直接有边相连,这三个点组成的环就是三元环. 三元环的计数方法:记录图中每个点的度数,对于每条边将它定向.对于一条边,将度数大的点指向度数小的点,如果度数相同就将编号小的点指向编号大的点.计数时枚举每个点,对于每个点x枚举它的出边,并将出边指向的点y打标记,对于所有出边指向的点y再枚举出边