1. 程式人生 > >HDU 2167 狀壓dp方格取數

HDU 2167 狀壓dp方格取數

並不是 運行時間 can line 獲得 pac har 轉移 space

題意:給出一個數表,規定取出一個數後周圍的八個數都不可取,求可獲得的最大數字和 思路:狀態壓縮dp,每一行的取數方法為狀態,顯然,由於取數規則的限制,可取的狀態並不是 1<<size_col,而是非常有限的,我們可以預處理出狀態(不超過1600個),大大降低時間復雜度, 運行時間:140ms

#include <bits/stdc++.h>
using namespace std;
int dp[16][1600],sta[1600],len,n;
int g[15][15];
void init()
{
    for(int i=0;i<(1<<15);i++)if
(!(i&(i<<1))&&!(i&(i>>1)))sta[len++]=i;//預處理出所有可取狀態 } int Res[16][1600];//加個記憶化,避免重復的計算 inline int calstatus(int row,int sta,int j)//計算出row行這個狀態所有數字的的sum { if(Res[row][j]) return Res[row][j]; int res=0; for(int j=0;j<n;j++){ if(sta&1) { res
+=g[row][j]; } sta>>=1; } return Res[row][j]=res; } int main() { init(); while (n=0,~scanf("%d",&g[0][n++])) { memset(Res,0,sizeof(Res)); memset(dp,0, sizeof(dp));//初始化 //坑爹輸入部分 while (true) { scanf("%d",&g[0
][n++]); if(getchar()==\n)break; } for(int i=1;i<n;i++) for(int j=0;j<n;j++)scanf("%d",&g[i][j]); //第一行預處理 for(int i=0;i<n;i++) for(int j=0;j<len&&sta[j]<(1<<n);j++)dp[0][j]=calstatus(0,sta[j],j); int ans=0; for(int i=1;i<n;i++) { for(int j=0;j<len&&sta[j]<(1<<n);j++) { for(int k=0;k<len&&sta[k]<(1<<n);k++) if(!(sta[k]&(sta[j]<<1))&&!(sta[k]&(sta[j]>>1))&&!(sta[k]&sta[j])){//左移右移與不移,兩個狀態都不沖突,進行狀態轉移 dp[i][k]=max(dp[i][k],dp[i-1][j]+calstatus(i,sta[k],k)); ans=max(ans,dp[i][k]); } } } printf("%d\n",ans); } return 0; }

HDU 2167 狀壓dp方格取數