Loading

旅游景点 Tourist Attractions 做题感受

细节较多,推荐阅读原题

这个题调了今天(早预备+体育课+第五节+中午20分钟+晚新闻+晚三),终于搞出来了,写个题解(根本不是题解,就是一划水帖子)纪念一下

这道题思路还是很好想的,我一开始就想到了对范围较小的\(k\)下手,然后很愉快的推出方程,然后开始了各种错误

错误1:一开始把\(define\ int\ long\ long\),空间直接翻倍直接炸成\(0\),以后要计算一下是否爆\(int\)再操作,同时学会了空间计算方法

int 4个字节 , long long 8个字节 , bool 1个字节 , 一个 bit \(1/4\)个字节 , \(1024 * 1024\)字节等于\(1MB\)

错误2:先枚举顶点再枚举状态,历史总是惊人的相似,我没次都要犯这个沙雕错误,导致调试半天(就做了3个枚举两层三次都错了)

错误3:由于学校oj上空间严格给的\(357MB\),所以不能把起点和终点也进行状态压缩,需要额外i跑两边\(dj\)求出每个点到起点和终点的距离

错误4:由于空间比较卡的慌,所以我们需要利用一下\(0\)这个空间,可以直接让空间减小一倍

错误5:\(cmath里面的log\)函数并不稳定,最好自己手写\(O(n)\)预处理

lg [0] = -1 ; 
for( R i = 1 ; i <= ( 1 << s ) ; i ++ ) lg [i] = lg [i / 2] + 1 ;

错误6:由于没有计算起点和终点,所以要特判一下\(k==0\)的情况,直接$dj\ 1 - n $的最短路

错误7:经典错误,\(dj\)里面初始化不能初始化成0x7f,要初始化成0x3f.

没啥了吧

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <iostream>
#include <queue>
#include <cmath>
#define R register int 
//#define int long long
#define PI pair< int , int > 
#define mp make_pair

using namespace std ;
const int N = 2e4 + 10 ;
const int M = 4e5 + 10 ;
typedef long long L ;
typedef double D ;

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

int n , m , ks , qs , s [N] , dis [N] , fg [N] , f [21][1 << 21] ;  // f [i][j]  表示j状态且目前出去i点的MIN Ans : f [ks(n)][(i << ks )- 1]
int x , y , z , head [N] , cnt , ds [25][25] , lg [1 << 22] ;
struct E{ int fr , to , w , next ; } a [M] ;
priority_queue< PI , vector< PI > , greater< PI > > q ;

inline void debug( int x ){ cout << bitset<10> ( x ) << endl ; }

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

inline void dj( int x ){
	memset( dis , 0x3f , sizeof( dis ) ) , memset( fg , 0 , sizeof( fg ) ) ; 
	dis [x] = 0 ; q.push( mp ( 0 , x ) ) ;
	while( !q.empty() ){
		int x = q.top().second ; q.pop() ;
		if( fg [x] ) continue ; fg [x] = 1 ;
		for( R i = head [x] ; ~i ; i = a [i].next ){
			int y = a [i].to ;
			if( dis [y] > dis [x] + a [i].w )
				dis [y] = dis [x] + a [i].w , q.push( mp( dis [y] , y ) ) ;
		}
	} x -- ;
//	printf( "THIS IS%d\n" , x ) ;
//	for( R i = 0 ; i < n ; i ++ ) printf( "%d %d\n" , i , dis [i] ) ; 
	for( R i = 1 ; i <= ks ; i ++ ) ds [x][i - 1] = dis [i] ; ds [x][ks] = dis [n - 1] ;
//	for( R i = 0 ; i <= ks ; i ++ ) printf( "%d\n" , ds [x][i] ) ; //printf( "%d\n" , ds [x][ks + 1] ) ;
}

inline void dsj(){
	memset( dis , 0x3f , sizeof( dis ) ) , memset( fg , 0 , sizeof( fg ) ) ; 
	dis [0] = 0 ; q.push( mp ( 0 , 0 ) ) ;
	while( !q.empty() ){
		int x = q.top().second ; q.pop() ;
		if( fg [x] ) continue ; fg [x] = 1 ;
		for( R i = head [x] ; ~i ; i = a [i].next ){
			int y = a [i].to ;
			if( dis [y] > dis [x] + a [i].w )
				dis [y] = dis [x] + a [i].w , q.push( mp( dis [y] , y ) ) ;
		}
	}
	for( R i = 1 ; i <= ks ; i ++ ) ds [24][i - 1] = dis [i] ; ds [24][ks] = dis [n - 1] ;
}

inline void ddj(){
	memset( dis , 0x3f , sizeof( dis ) ) , memset( fg , 0 , sizeof( fg ) ) ; 
	dis [0] = 0 ; q.push( mp ( 0 , 0 ) ) ;
	while( !q.empty() ){
		int x = q.top().second ; q.pop() ;
		if( fg [x] ) continue ; fg [x] = 1 ;
		for( R i = head [x] ; ~i ; i = a [i].next ){
			int y = a [i].to ;
			if( dis [y] > dis [x] + a [i].w )
				dis [y] = dis [x] + a [i].w , q.push( mp( dis [y] , y ) ) ;
		}
	} printf( "%d\n" , dis [n - 1] ) ;  exit( 0 ) ;
}

inline int lb( int x ){ return x & -x ; } 

void sc(){
	
	n = read() , m = read() , ks = read() ; memset( head , -1 , sizeof( head ) ) ;
	lg [0] = -1 ; for( R i = 1 ; i < ( 1 << 22 ) ; i ++ ) lg [i] = lg [i / 2] + 1 ;
//	for( R i = 0 ; i <= n ; i ++ ) printf( "%lld\n" , lg [i] ) ;
	for( R i = 1 ; i <= m ; i ++ ) x = read() , y = read() , z = read() , x -- , y -- , add( x , y , z ) , add( y , x , z ) ;
	if( !ks ) ddj() ; qs = read() ; 
	for( R i = 1 ; i <= qs ; i ++ ){
		x = read() , y = read() ; x -=2 , y -= 2 ;
		s [x] |= ( 1 << y ) ; //debug( s [x] ) ;
 	}  for( R i = 1 ; i <= ks ; i ++ ) dj( i ) ; 
 	dsj() ;
}


void works(){
	memset( f , 0x3f , sizeof( f ) ) ;
	for( R i = 0 ; i <= ks ; i ++ ) f [i][1 << i] = ds [24][i] ;
	for( R j = 1 ; j < 1 << ks ; j ++ ){
		for( R i = 0 ; i <= ks ; i ++ ){
			for( R k = j ; k ; k -= lb( k ) ){
				int t = lb( k ) , fs = j ^ t ; 
	//			t = (int)( (D)(log(t))/(D) (log(2)) ) ; //t ++ ;
				t = lg [t] / lg [2] ; 
				if( fs & s [t] ) continue ;
				if( ! (( fs >> i ) & 1 ) ) continue ;
	//			if( ! (() >> ( )) )
				
				f [t][j] = min( f [t][j] , f [i][fs] + ds [i][t] ) ;
		//		printf( "%d " , i ) , debug( fs ) ;
		//		printf( "%d " , t ) , debug( j ) ; printf( "LONG%d " , ds [i][t] ) ;
		//		printf( "%d %d\n" , f [t][j] , f [i][fs] ) , puts( "" ) ;
			}
		} 
	} int ans = 0x3f3f3f3f ;
	for( R i = 0 ; i <= ks ; i ++ ) ans = min( ans , f [i][(1 << ks)  - 1] + ds [i][ks] ) ;
	printf( "%d\n" , ans ) ;
}

signed main(){
//	freopen( "1.out" , "w" , stdout ) ;
//	printf( "LOG%d\n" , (int)( (D)(log(9))/(D) (log(2)) )) ;
	sc() ;
	works() ;
	return 0 ;
}


posted @ 2021-04-23 21:47  Soresen  阅读(96)  评论(2)    收藏  举报