题目
题意:一个图
G
G
G的线图
L
(
G
)
L(G)
L(G)为把所有
G
G
G中的边变为点,
G
G
G中共点的不同边所变为的点在
L
(
G
)
L(G)
L(G)中有一条边相连,求
L
k
(
G
)
=
L
(
L
(
L
.
.
.
(
G
)
)
)
L^k(G) = L(L(L...(G)))
Lk(G)=L(L(L...(G)))这个图中的最大团(一个点集其中任意两点有连边)大小及有多少个最大团。
题解:
众所周知
k
=
0
k = 0
k=0 时在 G 中求解最大团是个
N
P
−
H
a
r
d
NP-Hard
NP−Hard 问题,但是
k
=
1
k = 1
k=1 时只有 G 中的共点边或者
三元环才能构成一个
L
(
G
)
L(G)
L(G) 中大小
≥
2
≥ 2
≥2 的团,因此在
L
k
(
G
)
L_k(G)
Lk(G) 求解最大团时只需要考虑
L
k
−
1
(
G
)
L_{k−1}(G)
Lk−1(G) 中的点
(计算其度数)或者三元环。
首先分情况考虑
L
k
−
1
(
G
)
L_k−1(G)
Lk−1(G) 中每个点的度数,
• k = 1,直接计算;
• k = 2,
L
(
G
)
L(G)
L(G) 中每个点对应 G 中一条边 (u; v),度数是 degu + degv − 2,也可以直接计算;
• k = 3,
L
2
(
G
)
L_2(G)
L2(G) 中每个点对应 L(G) 中一条边,对应 G 中一对共点边
(
(
u
;
v
)
;
(
u
;
w
)
)
((u; v); (u; w))
((u;v);(u;w)),其中
v
=
w̸
v =\not w
v=w,
度数是
2
d
e
g
u
+
d
e
g
v
+
d
e
g
w
−
6
2deg_u + deg_v + deg_w − 6
2degu+degv+degw−6,可以枚举 u 来计算;
• k = 4,
L
3
(
G
)
L_3(G)
L3(G) 中每个点对应
L
2
(
G
)
L_2(G)
L2(G) 中一条边, 对应 L(G) 中一对共点边, 对应 G 中
一对有公共边的共点边对
(
(
(
u
;
v
)
;
(
u
;
w
)
)
;
(
(
u
;
v
)
;
(
v
;
x
)
)
)
(((u; v); (u; w)); ((u; v); (v; x)))
(((u;v);(u;w));((u;v);(v;x))), 其中
u
=
x̸
;
v
=
w̸
u =\not x; v =\not w
u=x;v=w, 度数是
3
d
e
g
u
+
3
d
e
g
v
+
d
e
g
w
+
d
e
g
x
−
14
3deg_u + 3deg_v + deg_w + deg_x − 14
3degu+3degv+degw+degx−14,或者是
(
(
(
u
;
v
)
;
(
u
;
w
)
)
;
(
(
u
;
v
)
;
(
u
;
x
)
)
)
(((u; v); (u; w)); ((u; v); (u; x)))
(((u;v);(u;w));((u;v);(u;x))),其中
v
;
w
;
x
v; w; x
v;w;x 两两不同,度数是
4
d
e
g
u
+
2
d
e
g
v
+
d
e
g
w
+
d
e
g
x
−
14
4deg_u + 2deg_v + deg_w + deg_x − 14
4degu+2degv+degw+degx−14,两种情况均可以枚举
(
u
;
v
)
(u; v)
(u;v) 来计算。
预处理每个点的相邻点中最大的三种点度及其出现次数,即可在关于 n 和 m 线性的时间内完成这
一部分计算。
但是如果此时计算出的最大团大小 ≤ 3,还需要考虑
L
k
−
1
(
G
)
L_{k−1}(G)
Lk−1(G) 中的三元环,不难证明此时 G 中每个
点的度数都不超过 3,除非
k
=
2
k = 2
k=2,此时允许某些连通块是完全二分图
K
1
,
4
K_{1,4}
K1,4,进一步可以证明迭代一次
至多使边数乘以 2,于是可以直接模拟出
L
k
−
1
L_{k−1}
Lk−1 之后枚举所有三元环,这部分计算也是在关于 n 和 m 线
性的时间内完成的。标程采用的方法是当 k ≥ 2 时模拟出
L
k
−
2
(
G
)
L_{k−2}(G)
Lk−2(G) 之后枚举三元环并计算三条边共点的
方案数,实际上没有差别。
最后需要注意的是,最大团大小为 0 时方案数是 1(已经包括在样例中),大小为 1 时上述方法会
计算每个团两次,需要将答案除以 2。
实现:分类讨论+三元环计数。。。。。。照题解计算同时注意相同度数的细节处理,枚举顺序防算重的细节处理即可AC打完代码发现莫名上了5KB,模拟
L
(
)
L()
L()变换时可以STOSTL大法。
AC Code:
#include<bits/stdc++.h>
#define F first
#define S second
#define mp make_pair
#define pb push_back
#define mod 1000000007
using namespace std;
int T,n,m,k,deg[400005],fcnt[100005],scnt[100005],tcnt[100005],siz[400005];
vector<pair<int,int> >G[400005],nG[400005];
inline bool cmp(const pair<int,int>&a,const pair<int,int>&b){
return deg[a.F] > deg[b.F];
}
bool vis[400005];
int cal3(int tp=0){
for(int p=1;p<=k-2;p++){
int nn = m , nm = 0;
for(int i=1;i<=nn;i++) nG[i].clear();
for(int i=1;i<=n;i++)
for(int j=0;j<G[i].size();j++)
for(int k=j+1;k<G[i].size();k++){
nG[G[i][j].S].pb(mp(G[i][k].S,++nm));
nG[G[i][k].S].pb(mp(G[i][j].S,nm));
}
n = nn , m = nm;
swap(G,nG);
}
int ret = 0;
if(!tp){
for(int i=1;i<=n;i++){
siz[i] = G[i].size();
if(siz[i] >= 3)
ret = (ret + siz[i] * 1ll * (siz[i]-1) * (siz[i]-2) / 6) % mod;
}
}
for(int i=1;i<=n;i++)
for(int j=0;j<G[i].size();j++)
if(siz[i] < siz[G[i][j].F] || (siz[i] == siz[G[i][j].F] && i < G[i][j].F))
{
if(j < G[i].size() - 1)
swap(G[i][j],G[i].back());
G[i].pop_back();
j--;
}
for(int i=1;i<=n;i++){
for(int j=0;j<G[i].size();j++)
vis[G[i][j].F] = 1;
for(int j=0,v;j<G[i].size();j++){
v = G[i][j].F;
for(int k=0;k<G[v].size();k++)
if(vis[G[v][k].F])
ret ++;
}
for(int j=0;j<G[i].size();j++)
vis[G[i][j].F] = 0;
}
return ret;
}
int main(){
for(scanf("%d",&T);T--;){
scanf("%d%d%d",&n,&m,&k);
int ans = 0 , ret = 0;
for(int i=1;i<=n;i++)
G[i].clear(),deg[i]=0;
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].pb(mp(v,i)),G[v].pb(mp(u,i));
deg[u] ++ , deg[v] ++;
}
for(int u=1;u<=n;u++){
sort(G[u].begin(),G[u].end(),cmp);
int j=1;
for(;j<G[u].size() && deg[G[u][j].F] == deg[G[u][0].F];j++);
fcnt[u] = j;
j = 2;
for(;j<G[u].size() && deg[G[u][j].F] == deg[G[u][1].F];j++);
scnt[u] = j;
j = 3;
for(;j<G[u].size() && deg[G[u][j].F] == deg[G[u][2].F];j++);
tcnt[u] = j;
}
if(k == 1){
for(int i=1;i<=n;i++){
if(ans < deg[i]) ans = deg[i] , ret = 0;
if(deg[i] == ans) ret ++;
}
if(ans <= 3){
int t = cal3(1);
if(t && ans < 3) ans = 3 , ret = t;
else ret = (ret + t) % mod;
}
if(ans == 1)
ret /= 2;
if(ans == 0)
ret = 1;
printf("%d %d\n",ans,ret);
}
if(k >= 2){
if(k==2){
for(int i=1;i<=n;i++){
for(int j=0,v;j<G[i].size();j++)
if((v = G[i][j].F) > i){
if(deg[v] + deg[i] - 2 > ans) ans = deg[v] + deg[i] - 2 , ret = 0;
if(ans == deg[v] + deg[i] - 2) ret++;
}
}
}
if(k==3){
for(int i=1;i<=n;i++)
if(G[i].size() >= 2){
int u = G[i][0].F , v = G[i][1].F;
if(deg[u] + deg[v] + 2 * deg[i] - 6 > ans)
ans = deg[u] + deg[v] + 2 * deg[i] - 6 , ret = 0;
if(deg[u] + deg[v] + 2 * deg[i] - 6 == ans){
if(deg[u] == deg[v]) ret = (ret + fcnt[i] * (fcnt[i]-1ll) / 2) % mod;
else ret = (ret + scnt[i]-1) % mod;
}
}
}
if(k==4){
for(int i=1;i<=n;i++){
for(int j=0,v,w,x;j<G[i].size();j++){
v = G[i][j].F;
if(G[i].size() >= 2 && G[v].size() >= 2 && i>v){
w = G[i][j==0].F , x = (G[v][0].F == i ? G[v][1].F : G[v][0].F);
if(ans < 3 * deg[i] + 3 * deg[v] + deg[w] + deg[x] - 14) ans = 3 * deg[i] + 3 * deg[v] + deg[w] + deg[x] - 14 , ret = 0;
if(ans ==3 * deg[i] + 3 * deg[v] + deg[w] + deg[x] - 14){
int tmp = 1;
if(j != 0){
if(deg[w] == deg[v]) tmp = tmp * 1ll * (fcnt[i] - 1)% mod;
else tmp = tmp * 1ll * (fcnt[i]) % mod;
}
else{
tmp = tmp * 1ll * (scnt[i]-1) % mod;
}
if(G[v][0].F == i){
tmp = tmp * 1ll * (scnt[v]-1) % mod;
}
else{
if(deg[x] == deg[i]) tmp = tmp * 1ll * (fcnt[v] - 1) % mod;
else tmp = tmp * 1ll * (fcnt[v]) % mod;
}
ret = (ret + tmp) % mod;
}
}
if(G[i].size() >= 3){
w = G[i][j==0].F;
if(j<=1) x = G[i][2].F;
else x = G[i][1].F;
if(ans < 4 * deg[i] + 2 * deg[v] + deg[w] + deg[x] - 14) ans = 4 * deg[i] + 2 * deg[v] + deg[w] + deg[x] - 14 , ret = 0;
if(ans ==4 * deg[i] + 2 * deg[v] + deg[w] + deg[x] - 14){
int tmp = 1;
if(deg[w] == deg[x]){
if(j == 0){
tmp = 1ll * tmp * ((scnt[i]-1ll) * (scnt[i]-2) / 2 % mod) % mod;
}
else{
if(deg[w] == deg[v]) tmp = 1ll * tmp * ((fcnt[i]-1ll) * (fcnt[i]-2) / 2 % mod) % mod;
else tmp = 1ll * tmp * (fcnt[i] * (fcnt[i]-1ll) / 2 % mod) % mod;
}
}
else{
if(j <= 1){
tmp = 1ll * tmp * (tcnt[i]-2) % mod;
}
else{
tmp = 1ll * tmp * (scnt[i]-1) % mod;
}
}
ret = (ret + tmp)% mod;
}
}
}
}
}
if(ans <= 3){
int t = cal3(0);
if(ans < 3 && t) ans = 3 , ret = t;
else ret = (ret + t) % mod;
}
if(!ans) ret = 1;
if(ans == 1) ret /= 2;
printf("%d %d\n",ans,(ret+mod)%mod);
}
}
}