宝藏
考试的时候推出来了正确的式子,然后给自己证伪了,之后一直想能不能费用提前计算一波消除后效性,显然失败了。
我还是太菜了,\(\mathcal{ICEY}\)考场直接切掉,\(So \ Huge\).
先说一下被我证伪又经\(\mathcal{ICEY}\)证明的方法:
二进制每次扩展一条道路。
\(f[s]\)代表\(s\)状态下打通的道路,\(g[s][i]\)表示\(s\)状态下起点到达\(i\)点的长度。
这个方法看起来很玄学,因为容易让人们觉得他有后效性。
但是,发现一个事情,最优解必定是可以被一条一条道路扩展而计算出来的。
现在的问题是最优解到底为什么可以一直保存在我们的状态中而不被刷掉。
考虑最优解的性质,他如果当前的每一步都不是最优方案,那么他一定不是最优解。
这个是可以证明的。简单证明直接想最后一步,最后一步选择比他优的解一定比所谓的最优解优,然后数学归纳就可以证明。
既然他有至少一步是最优的,他就不会被刷掉。
大家也可以参考\(\mathcal{ICEY}\)的博客。
也可以从集合角度考虑,如果在当前节点更新一个节点有后效性,那么他一定会被一个没有后效性的状态最后刷新。
也就是到达每一个状态之后,刷新他的状态都枚举了。
如果还没懂,可以根据一下例子理解一下。

我们考虑由1为起点的情况。
0001->0 , 刷新0011 -> 1 , 0101 ->6
0011->1 , 刷新0111 -> 5
0101->6, 刷新1101 -> 14 , 想要刷新0111-> 7,但原来是5,所以失败了。
0111->5, 刷新1111 -> 17
1101->14,刷新1111-> 15
答案就是\(15\)
我考场上只想到0111这个状态转移的并不是全局最优解,没有考虑到全局最优解存在了1101里面,最后更新了答案。
状压存的信息确实很多,\(hack\)自己的时候谨慎一点。
既然这个思路没问题,那么方程因该很好搞
code
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <bitset>
#include <iostream>
#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 K = 14 ;
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 , p [K][K] , f [1 << K] , ans = 0x3f3f3f3f , num [1 << K][K] , mx , x , y ;
void sc(){
n = read() , m = read() ; mx = ( 1 << n ) - 1 ; memset( p , 0x7f , sizeof( p ) ) ;
for( R i = 1 ; i <= m ; i ++ ) x = read() , y = read() , p [x][y] = min( p [x][y] , read() ) , p [y][x] = p [x][y] ;
}
inline void clear( int x ){
memset( f , 0x3f , sizeof( f ) ) ;
memset( num , 0 , sizeof( num ) ) ;
f [1 << ( x - 1 )] = 0 ;
num[1 << ( x - 1 )][x] = 1 ;
}
inline void debug( int x ){ cout << bitset<10> ( x ) << endl ; }
void work(){
for( R i = 1 ; i <= n ; i ++ ){
clear( i ) ;
for( R k = 1 ; k <= mx ; k ++ ){
if( f [k] > (int) 1e8 ) continue ;
for( R j = 1 ; j <= n ; j ++ ){
if( !( ( k >> ( j - 1 ) ) & 1 ) ) continue ;
for( R l = 1 ; l <= n ; l ++ ){
if( ( k >> ( l - 1 ) ) & 1 ) continue ;
if( p [l][j] > (int) 5e5 ) continue ;
if( f [k | ( 1 << ( l - 1 ) )] > f [k] + num [k][j] * p [j][l] ){
// printf( "%ld %ld %ld %ld %ld %ld\n" , j , l , f [k | ( 1 << ( l - 1 ) )] , f [k] + num [k][j] * p [j][l] , num [k][j] , p [j][l] ) ;
f [k | ( 1 << ( l - 1 ) )] = f [k] + num [k][j] * p [j][l] ;
// debug( k | ( 1 << ( l - 1 ) ) ) , printf( "%ld\n" , f [k | ( 1 << ( l - 1 ) )] ) ;
for( R m = 1 ; m <= n ; m ++ ) num [k | ( 1 << ( l - 1 ) )][m] = num [k][m] ;
num[k | ( 1 << ( l - 1 ) )][l] = num [k][j] + 1 ;
}
}
}
}// printf( "A%ld %ld\n" , f [mx] , ans ) ;
ans = min( ans , f [mx] ) ;
//printf( "A%ld %ld\n" , f [mx] , ans ) ;
} printf( "%ld\n" , ans ) ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}
还有一个一次扩展一层的思路,不过需要预处理一些东西。
思路蓝书写的非常清楚,预处理出来转移到每个状态的可能状态和代价就行了,不再复读。
code
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <bitset>
#include <iostream>
#include <vector>
#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 K = 14 ;
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 , p [K][K] , lg [1 << K] ;
int ep [1 << K] , rd [1 << K][K] ;
vector< int > cost [1 << K] , fg [1 << K] ;
int f [K][1 << K] , ans = 0x3f3f3f3f , mx , x , y ;
void sc(){
n = read() , m = read() ; mx = ( 1 << n ) - 1 ; memset( p , 0x7f , sizeof( p ) ) ;
for( R i = 1 ; i <= m ; i ++ ) x = read() , y = read() , p [x][y] = min( p [x][y] , read() ) , p [y][x] = p [x][y] ;
}
inline void clear( int x ){
memset( f , 0x3f , sizeof( f ) ) ;
f [1][1 << ( x - 1 )] = 0 ;
}
inline void debug( int x ){ cout << bitset<10> ( x ) << endl ; }
inline int lb( int x ){ return x & -x ; }
void pre(){
memset( rd , 0x7f , sizeof( rd ) ) ;
for( R i = 1 ; i <= mx ; i ++ ){
int s = i ; // debug( i ) ;
for( R j = 1 ; j <= n ; j ++ ){
if( ! ( ( i >> ( j - 1 ) ) & 1 ) ) continue ;
for( R k = 1 ; k <= n ; k ++ ){
if( p [j][k] > (int) 5e5 ) continue ;
s |= ( 1 << ( k - 1 ) ) ;
rd [i][k] = min( rd [i][k] , p [j][k] ) ;
}
} ep [i] = s ; // debug( s ) ; puts( "" ) ;
}
lg [0] = -1 ; for( R i = 1 ; i < 1 << K ; i ++ ) lg [i] = lg [i / 2] + 1 ;
for( R i = 1 ; i <= mx ; i ++ ){
for( R j = 1 ; j <= mx ; j ++ ){
if( ( i & j ) != j ) continue ; //枚举子集
if( ( i & ep [j] ) != i ) continue ;
if( i == j ) continue ;
fg [i].push_back( j ) ;
int s = i ^ j , ct = 0 ;
for( ; s ; s -= lb ( s ) ){
int k = lg[lb( s )] + 1 ;
// debug( i ) , debug( j ) ;
// printf( "%ld\n\n\n" , k ) ;
ct += rd [j][k] ;
} cost [i].push_back( ct ) ;
}
}
// for( R i = 1 ; i <= mx ; i ++ )
// for( R j = 0 ; j < fg [i].size() ; j ++ ){
// debug( i ) , debug( fg [i][j] ) ;
// printf( "%ld\n" , cost [i][j] ) ;
// }
}
void work(){
pre() ;
for( R st = 1 ; st <= n ; st ++ ){
clear( st ) ;
for( R dep = 1 ; dep <= n ; dep ++ ){
for( R i = 1 ; i <= mx ; i ++ ){
for( R j = 0 ; j < fg [i].size() ; j ++ ){
f [dep][i] = min( f [dep][i] , f [dep - 1][fg [i][j]] + cost [i][j] * ( dep - 1 ) ) ;
}
} ans = min( ans , f [dep][mx] ) ;
}
} printf( "%ld\n" , ans ) ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}

浙公网安备 33010602011771号