Loading

星际旅行

本弱跟正解思路一点都对不上。

把每个边拆成两个边,也就是在原图中去掉两条边,使图是一个欧拉路
欧拉路就是可以一笔画出来的图。
类似的还有欧拉回路,就是可以一笔画出来还能回到起点的。

判定:欧拉路判定,当且仅当所有点的度都为偶数或者有且仅有两个点度为奇数。
两个奇数的点就是起点和终点。
欧拉回路判定:当且进当所有的点度均为偶数。

判定挺好理解的,得让进来这个点的边都有边出去。

然后拆两条边使他为欧拉路,我们需要先看图连不连通。
注意这里的连通是边之间连不联通,而不是点之间连不联通。

可以通过\(dfs\)实现,不过需要一手操作:手动模拟栈实现\(dfs\)

然后统计所有点的度,分类讨论
\(pre\):由于所有边都拆成两条,导致所有的点的度必定是偶数。
1.去掉两个自环,\(C_{cnt}^{2}\),把组合手动展开就行了。
2.去掉一个自环和一条边,那么就出现了两个度为奇数的点,不过也是合法情况。
3.去掉两个边,不过这两个边必须有公共顶点,这样一个点度\(-2\),两个点度\(-1\),出现两个度为奇数的点,也是合法的。

图论的题,如果不是\(dp\),那么推性质,转化题意啥的是少不了的,不断琢磨他给的条件,正反都用用。
各种奇思怪想也都想想,没准就是正解。
实在不行呼一个大概率正确的伪结论上去有时候也是不错的选择。

code
#include <cstring>
#include <algorithm>
#include <cstdio>
#define mp make_pair
#define R register int
#define int long 
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 1e5 + 10 ;
                  	
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

inline void wap( int &a , int &b ){ a = a ^ b , b = a ^ b , a = a ^ b ; }
inline int mins( int a , int b ){ int zt = b - a ; return a + ( zt & ( zt >> 31 ) ) ; }
inline int maxs( int a , int b ){ int zt = b - a ; return b - ( zt & ( zt >> 31 ) ) ; }
inline int abss( int a ){ int zt = a >> 31 ; return ( a + zt ) ^ zt ; }

int n , m , dr [N] , root , knt , x , y , lnt , st [N << 1] , top ;
L ans ; bool fg [N << 1] ;

int net [N << 1] , fr [N << 1] , to [N << 1] , head [N] , cnt = 1 ; 

inline void add( int f , int t ){
	fr [++ cnt] = f ;
	to [cnt] = t ;
	net [cnt] = head [f] ;
	head [f] = cnt ;
}

void sc(){
	n = read() , m = read() ; memset( head , -1 , sizeof( head ) ) ;
	for( R i = 1 ; i <= m ; i ++ ){
		x = read() , y = read() ; 
		if( x != y ) dr [x] ++ , dr [y] ++ , add( x , y ) , add( y , x ) , root = x ;
		else knt ++ ;
	}
}

void dfs( int x ){
	st [++ top] = x ;
	
	while( top ){
		int x = st [top] ;
		R i = head [x] ;
		while( ~i && fg [i] ) i = net [i] ;
		if( ~i ){
			int y = to [i] ;
			fg [i] = fg [i ^ 1] = 1 ;
			head [x] = net [i] ;
			st [++ top] = y ;
		}
		else top -- ;
	}
}

void work(){
	if( !root ) puts( "0" ) , exit( 0 ) ;
//	printf( "%ld %ld\n" , root , cnt ) ; 
	dfs( root ) ;
//	printf( "%ld\n" , lnt ) ; 
	for( R i = 2 ; i <= cnt ; i ++ )
		if( !fg [i] ) puts( "0" ) , exit( 0 ) ;
	ans = 1ll * knt * ( 0ll + knt - 1 ) / 2ll ;
	ans += 1ll * knt * ( 0ll + m - knt ) ;
	for( R i = 1 ; i <= n ; i ++ ) 
		ans +=  ( 1ll * dr [i] * ( dr [i] - 1ll ) ) / 2ll ; //强制类型转换,乘到括号外面没用!
	printf( "%lld\n" , ans ) ; 
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}

代码直接理解就挺好理解的。
非递归\(dfs\)可以扩展到任何\(dfs\),我自己也实现了一个树形\(dp\)
不过由于一般的\(dfs\)深度没有那么深,所以也没必要写成非递归。
有兴趣的还是可以看看的。

偷天换日 code


#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register int

using namespace std ;
typedef long long L ;
const int N = 2.5e3 + 10 ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , t , x , ws , c , cnt , pos , head [N] ; 
struct T{ int to , next , w ; } a [N] ; 
inline void add( int f , int t , int w ){ a [++ cnt].to = t , a [cnt].w = w , a [cnt].next = head [f] , head [f] = cnt ; }
int g [N] , f [N][N] , st [N] , top , fa [N] , byfa [N] ;

inline void init( int fa ){
	t = read() , x = read() ; 
	add( fa , ++ pos , t * 2 ) ;
	if( x != 0 ){ 
		int u = pos ; 
		for( R i = 1 ; i <= x ; i ++ )
		ws = read() , c = read() ,
		add( u , ++ pos , c ) , g [pos] = ws ;  
	} 
	
	else { int u = pos ; init( u ) , init( u ) ; }
}

void sc(){
	n = read() ; n -- ;
	memset( head , -1 , sizeof( head ) ) ;
	init( 0 ) ;
}

inline void dfs( int u ){
/*	for( R i = head [u] ; ~i ; i = a [i].next ){
		int y = a [i].to ; 
		dfs( y ) ;
		printf( "%d %d %d\n" , u , y , i ) ;
		for( R j = n ; j >= a [i].w ; j -- )
		for( R k = 0 ; k <= j - a [i].w ; k ++ )
		f [u][j] = max( f [u][j] , f [u][k] + f [y][j - a [i].w - k] + g [y] ) ; 
		for( R j = n ; j >= 0 ; j -- )
		printf( "%d %d %d %d\n" , u , y , j , f [u][j] ) ;
	}*/
	
	st [++ top] = u ;
	
	while( top ){
		int x = st [top] ;
		R i = head [x] ;
		if( ~i ){
			int y = a [i].to ;
			fa [y] = x ;
			byfa [y] = i ;
			st [++ top] = y ;
			head [x] = a [i].next ;
		}
		else{
			int y = x ;
			x = fa [x] ;
			i = byfa [y] ;
			if( x == y ) { top -- ; continue ; }
			for( R j = n ; j >= a [i].w ; j -- )
			for( R k = 0 ; k <= j - a [i].w ; k ++ )
			f [x][j] = max( f [x][j] , f [x][k] + f [y][j - a [i].w - k] + g [y] ) ; 
			top -- ;
		}
	}
	
}

void work(){
	dfs( 0 ) ;
	printf( "%d\n" , f [0][n] ) ;
}

signed main(){
	sc() ;
	work() ;
	return 0 ;
}

posted @ 2021-06-27 19:36  Soresen  阅读(112)  评论(0)    收藏  举报