Description
给定一个无自环重边的无向图,求这个图的三元环的个数以及补图的三元环个数。
n≤105,m≤105
PS. 可以在这里交
Analysis
这个东西 首先我们可以用BZOJ 2916 [Poi1997]Monochromatic Triangles的方法算出原图三角形和补图三角形的个数之和 然后我们再算出原图三角形的个数就好了
以下的代码都是求原图三角形的个数 复杂度
O(mm−−√)
一般情况下跑得飞快
ps不知道哪里可以交啊写的代码没测过就放上来还说跑得快我也很不要脸啊
Solution1
首先我们可以考虑按阈值
m−−√
把点分为两类
[奇葩方法]三元环题解
将所有点分成两类:度数 < sqrt(m)的和度数 > sqrt(m)的.
先求包含第一类点的三元环个数.
由于边很少,所以枚举2条边即可.由于一个点的度不超过sqrt(m),所以一条边最多被枚到(sqrt(m))次,最多枚M条边,所以这个操作时O(m*sqrt(m))的.
再求不包含第一类点的三元环个数.
由于每条边贡献2个度,所以二类点的数量是O(sqrt(m))级的.直接枚举三个点,复杂度O((sqrt(m))^3)=O(m*sqrt(m))
所以算法总的复杂度是O(m*sqrt(m))的.
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#define push_back pb
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=200005;
namespace HashMap{
const int P=1000007,seed=2333;
int u[N<<1],v[N<<1],next[N<<1];
int head[P],inum;
inline void add(int _u,int _v){
int t=(_u*seed+_v)%P;
u[++inum]=_u; v[inum]=_v; next[inum]=head[t]; head[t]=inum;
}
inline bool query(int _u,int _v){
int t=(_u*seed+_v)%P;
for (int p=head[t];p;p=next[p])
if (u[p]==_u && v[p]==_v)
return 1;
return 0;
}
}
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m;
int deg[N];
int s[N],pnt;
int Ans;
#define V1 G[p].v
#define V2 G[q].v
int main(){
int iu,iv;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++){
read(iu),read(iv);
add(iu,iv,++inum); add(iv,iu,++inum);
deg[iu]++,deg[iv]++;
HashMap::add(iu,iv),HashMap::add(iv,iu);
}
int B=sqrt(m);
for (int i=1;i<=n;i++)
if (deg[i]<=B){
for (int p=head[i];p;p=G[p].next)
if (!(deg[V1]<=B && V1<i))
for (int q=G[p].next;q;q=G[q].next)
if (!(deg[V2]<=B && V2<i))
if (HashMap::query(G[p].v,G[q].v))
Ans++;
}else
s[++pnt]=i;
for (int i=1;i<=pnt;i++)
for (int j=i+1;j<=pnt;j++)
if (HashMap::query(s[i],s[j]))
for (int k=j+1;k<=pnt;k++)
if (HashMap::query(s[j],s[k]) && HashMap::query(s[i],s[k]))
Ans++;
printf("%d\n",Ans);
return 0;
}
Solution2
可以证明似乎三角形的个数就是
O(mm−−√)
?
求无向图三元环的个数,这种做法是O(m*sqrt(m))的吗?
给定n个点m条边的稀疏图,对于每一条边,枚举两个端点中度数较少的端点的邻接点,判断是否构成三元环。这种做法的判断次数在m条边形成一个完全图时达到最大,即O(m*sqrt(m))。不知道这个结论是不是对的?
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#define push_back pb
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=200005;
namespace HashMap{
const int P=1000007,seed=2333;
int u[N<<1],v[N<<1],next[N<<1];
int head[P],inum;
inline void add(int _u,int _v){
int t=(_u*seed+_v)%P;
u[++inum]=_u; v[inum]=_v; next[inum]=head[t]; head[t]=inum;
}
inline bool query(int _u,int _v){
int t=(_u*seed+_v)%P;
for (int p=head[t];p;p=next[p])
if (u[p]==_u && v[p]==_v)
return 1;
return 0;
}
}
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m;
int u[N],v[N];
int deg[N];
int Ans;
#define V G[p].v
int main(){
freopen("t.in","r",stdin);
freopen("t2.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++){
read(u[i]),read(v[i]);
add(u[i],v[i],++inum); add(v[i],u[i],++inum);
deg[u[i]]++,deg[v[i]]++;
HashMap::add(u[i],v[i]),HashMap::add(v[i],u[i]);
}
for (int i=1;i<=m;i++){
int u=::u[i],v=::v[i];
if (deg[u]>deg[v]) swap(u,v);
for (int p=head[u];p;p=G[p].next)
if (v!=V && HashMap::query(v,V))
Ans++;
}
printf("%d\n",Ans/3);
return 0;
}
学习了这里的写法 其实是一样的 不过常数小很多
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#define push_back pb
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=200005;
namespace HashMap{
const int P=1000007,seed=2333;
int u[N<<1],v[N<<1],next[N<<1];
int head[P],inum;
inline void add(int _u,int _v){
int t=(_u*seed+_v)%P;
u[++inum]=_u; v[inum]=_v; next[inum]=head[t]; head[t]=inum;
}
inline bool query(int _u,int _v){
int t=(_u*seed+_v)%P;
for (int p=head[t];p;p=next[p])
if (u[p]==_u && v[p]==_v)
return 1;
return 0;
}
}
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m;
int deg[N];
int Ans;
#define V G[p].v
int s[N],pnt;
int main(){
int iu,iv;
freopen("t.in","r",stdin);
freopen("t3.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++){
read(iu),read(iv);
add(iu,iv,++inum); add(iv,iu,++inum);
deg[iu]++,deg[iv]++;
HashMap::add(iu,iv),HashMap::add(iv,iu);
}
for (int u=1;u<=n;u++){
pnt=0;
for (int p=head[u];p;p=G[p].next)
if (deg[u]<deg[V] || (deg[u]==deg[V] && u<V))
s[++pnt]=V;
for (int i=1;i<=pnt;i++)
for (int j=1;j<i;j++)
if (HashMap::query(s[i],s[j]))
Ans++;
}
printf("%d\n",Ans);
return 0;
}
UPD.找到题了 跑得并不快 555 好像大家各有奇技淫巧
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#define push_back pb
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=250005;
namespace HashMap{
const int P=1000007,seed=2333;
int u[N<<1],v[N<<1],next[N<<1];
int head[P],inum;
inline void add(int _u,int _v){
int t=(_u*seed+_v)%P;
u[++inum]=_u; v[inum]=_v; next[inum]=head[t]; head[t]=inum;
}
inline bool query(int _u,int _v){
int t=(_u*seed+_v)%P;
for (int p=head[t];p;p=next[p])
if (u[p]==_u && v[p]==_v)
return 1;
return 0;
}
}
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m;
int deg[N];
ll Ans;
int val[N];
#define V G[p].v
int s[N],pnt;
int main(){
int iu,iv;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=1;i<=n;i++) read(val[i]);
for (int i=1;i<=m;i++){
read(iu),read(iv);
add(iu,iv,++inum); add(iv,iu,++inum);
deg[iu]++,deg[iv]++;
HashMap::add(iu,iv),HashMap::add(iv,iu);
}
for (int u=1;u<=n;u++){
pnt=0;
for (int p=head[u];p;p=G[p].next)
if (deg[u]<deg[V] || (deg[u]==deg[V] && u<V))
s[++pnt]=V;
for (int i=1;i<=pnt;i++)
for (int j=1;j<i;j++)
if (HashMap::query(s[i],s[j]))
Ans+=max(val[u],max(val[s[i]],val[s[j]]));
}
printf("%lld\n",Ans);
return 0;
}