1. 程式人生 > >【Codeforces】CF 8 C Looking for Order(狀壓dp)

【Codeforces】CF 8 C Looking for Order(狀壓dp)

輸出 max blank ret ces clas pan force date

題目

傳送門:QWQ

分析

這種題不會做 吃棗藥丸。。。。。

想到狀壓已經經過的點。

然後更新時枚舉兩個點加進去。

復雜度$ {O(2^n \times n^2)}$。

涼涼。

真正的做法是每一個狀態只要找到一組解就break。這樣可以省掉一層n。

大致上就像lrj紫書的dp例題一樣,反正這個點都要選,那就先選了他。

還不是很懂這個神奇的break。。。。。

代碼

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=25, INF=1e9;
4 5 int dp[1<<maxn], dis[maxn][maxn], pre[1<<maxn]; 6 int x[maxn], y[maxn]; 7 8 int sqr(int x){ return x*x; } 9 10 int main(){ 11 scanf("%d%d",&x[0],&y[0]); 12 int n; scanf("%d",&n); 13 for(int i=1;i<=n;i++) { 14 scanf("%d%d",&x[i],&y[i]);
15 } 16 for(int i=0;i<=n;i++){ 17 for(int j=0;j<=n;j++){ 18 dis[i][j]=dis[j][i]=sqr(x[i]-x[j])+sqr(y[i]-y[j]); 19 } 20 } 21 22 memset(dp,127,sizeof(dp)); 23 24 dp[0]=0; 25 for(int S=0;S<(1<<n);S++){ 26 if(dp[S]>INF) continue
; 27 for(int i=1;i<=n;i++){ 28 if(S&(1<<i-1)) continue; 29 for(int j=1;j<=n;j++){ 30 if(S&(1<<j-1)) continue; 31 32 int prenum=dp[S|1<<(i-1)|1<<(j-1)]; 33 dp[S|1<<(i-1)|1<<(j-1)]=min(dp[S|1<<(i-1)|1<<(j-1)], dp[S]+dis[0][i]+dis[0][j]+dis[i][j]); 34 if(prenum>dp[S|1<<(i-1)|1<<(j-1)]){ 35 pre[S|1<<(i-1)|1<<(j-1)]=S; 36 } 37 } 38 break; 39 } 40 } 41 42 printf("%d\n",dp[(1<<n)-1]); 43 int now=(1<<n)-1; //從所有都齊的狀態開始逆推 44 while ( now!=0 ) 45 { 46 printf( "0 " ); 47 int update=now^pre[now]; 48 for ( int i=1; i<=n; i++ ) 49 if ( update&1<<i-1 ) 50 printf( "%d ", i ); //輸出本次拿的哪些物品 51 now=pre[now]; 52 } 53 puts("0"); 54 }

【Codeforces】CF 8 C Looking for Order(狀壓dp)