1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 int a[17][17] ; 6 int dp[17][1 << 17] ; 7 int n ; 8 9 int main () 10 { 11 // freopen ("a.txt" , "r" , stdin ) ; 12 int T ; 13 scanf ("%d" , &T ) ; 14 int ans = 0 ; 15 while (T--) { 16 scanf ("%d" , &n ) ; 17 for (int i = 0 ; i < n ; i++) { 18 for (int j = 0 ; j < n ; j++) { 19 scanf ("%d" , &a[i][j]) ; 20 } 21 } 22 for (int i = 0 ; i < n ; i++) { 23 for (int j = 0 ; j < 1 << n ; j++ ) { 24 dp[i][j] = -1 ; 25 } 26 } 27 for (int i = 0 ; i < n ; i++) { 28 dp[0][1 << i] = a[0][i] ; 29 } 30 for (int i = 1 ; i < n ; i++) { 31 for (int j = 0 ; j < 1 << n ; j++) { 32 if (dp[i - 1][j] != -1) { 33 for (int k = 0 ; k < n ; k++) { 34 if ( ! (j & 1 << k) ) { 35 dp[i][j | 1 << k] = max (dp[i][j | 1 << k] , dp[i - 1][j] + a[i][k] ) ; 36 } 37 } 38 } 39 } 40 } 41 printf ("Case %d: %d " , ++ans , dp[n - 1][(1 << n) - 1 ] ) ; 42 } 43 return 0 ; 44 }
先把“ 数据 ”存入 下标为 1 << 0 , 1 << 1 , 1 << 2 , 1 << n - 1的这几个位置,然后就是一般的dp过程了
状态压缩dp我觉得有两点蛮神奇的(当然能用数学方法证明的)
:
1,! ( j & 1 << k ) 这能让已经加过的滚蛋;orz
2,(1 << 0) + (1 << 1 ) + ... + (1 << n - 1) = (1 << n ) - 1 orz 不仔细看还真没发觉