HDU 6692 Line Graphs(分类讨论+三元环计数)

18 篇文章 0 订阅
3 篇文章 0 订阅

题目
题意:一个图 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 NPHard 问题,但是 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) Lk1(G) 中的点
(计算其度数)或者三元环。
首先分情况考虑 L k − 1 ( G ) L_k−1(G) Lk1(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+degw6,可以枚举 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+degx14,或者是 ( ( ( 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+degx14,两种情况均可以枚举 ( u ; v ) (u; v) (u;v) 来计算。
预处理每个点的相邻点中最大的三种点度及其出现次数,即可在关于 n 和 m 线性的时间内完成这
一部分计算。
但是如果此时计算出的最大团大小 ≤ 3,还需要考虑 L k − 1 ( G ) L_{k−1}(G) Lk1(G) 中的三元环,不难证明此时 G 中每个
点的度数都不超过 3,除非 k = 2 k = 2 k=2,此时允许某些连通块是完全二分图 K 1 , 4 K_{1,4} K1,4,进一步可以证明迭代一次
至多使边数乘以 2,于是可以直接模拟出 L k − 1 L_{k−1} Lk1 之后枚举所有三元环,这部分计算也是在关于 n 和 m 线
性的时间内完成的。标程采用的方法是当 k ≥ 2 时模拟出 L k − 2 ( G ) L_{k−2}(G) Lk2(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);
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值