星际旅行
本弱跟正解思路一点都对不上。
把每个边拆成两个边,也就是在原图中去掉两条边,使图是一个欧拉路
欧拉路就是可以一笔画出来的图。
类似的还有欧拉回路,就是可以一笔画出来还能回到起点的。
判定:欧拉路判定,当且仅当所有点的度都为偶数或者有且仅有两个点度为奇数。
两个奇数的点就是起点和终点。
欧拉回路判定:当且进当所有的点度均为偶数。
判定挺好理解的,得让进来这个点的边都有边出去。
然后拆两条边使他为欧拉路,我们需要先看图连不连通。
注意这里的连通是边之间连不联通,而不是点之间连不联通。
可以通过\(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 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号