CF11D A Simple Task

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/90084625

D e s c r i p t i o n Description

给定一张 G = ( n , m ) G=(n,m) 无向图,求环个数

n 19 , 0 m n\leq 19,0\leq m


S o l u t i o n Solution

f [ i ] [ j ] f[i][j] 表示经过了 i |i| 的这些点,终点为 j j ,起点为 l o w b i t ( i ) lowbit(i) 的方案数

边界: f [ 2 i ] [ i ] = 2 f[2^i][i]=2

转移显然:

i i 的第 k k 位不为1时,即第 i i 个点没有走过时, f [ i 2 k ] [ k ] = f [ i ] [ j ] f[i|2^k][k]=\sum f[i][j] ,否则不转移

如果 2 k = l o w b i t ( i ) 2^k=lowbit(i) ,则说明出现了环, a n s + = f [ i ] [ j ] ans+=f[i][j]

最后答案要排除无向图的干扰以及边界带来的计算误差, a n s = ( a n s m ) / 2 ans=(ans-m)/2

记得开 l o n g   l o n g long\ long ,然后空集不转移,这样就 w o r k   o u t work\ out

时间复杂度最坏 O ( 2 n × n 2 ) = 189267968 1.9 × 1 0 8 O(2^n\times n^2)=189267968‬\approx 1.9\times 10^8 ,空集不转移就过掉了


C o d e Code

#include<cstdio>
#define lb(x) (x&-x)
using namespace std;int n,m,t;
bool a[19][19];
long long ans,f[600001][19];
signed main()
{
	scanf("%d%d",&n,&m);
	t=1<<n;
	for(register int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),a[--x][--y]=a[y][x]=true;
	for(register int i=0;i<n;i++) f[1<<i][i]=1;
	for(register int i=1;i<t;i++)
	 for(register int j=0;j<n;j++)
	  if(f[i][j])//有值才转移
	   for(register int k=0;k<n;k++)
	    if(a[j][k]&&lb(i)<=(1<<k))
	     if(i>>k&1)
	      {
	      	if(1<<k==lb(i)) ans+=f[i][j];
	      }
	     else f[i|1<<k][k]+=f[i][j];
	printf("%lld",(ans-m)/2);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/90084625