hdu 1565 方格取數(1) 位壓縮動態規劃
阿新 • • 發佈:2019-01-29
hdoj 1565 dp
方格取數(1)
Time Limit: 1000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1162 Accepted Submission(s): 415
從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測試例項包括一個整數n 和n*n個非負數(n<=20)
Output 對於每個測試例項,輸出可能取得的最大的和
Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188
這個問題可以用網路流來解決 最大點權獨立集
這裡由於資料小 我用動態規劃解決
設二進位制1為取該數 0為不取
設dp[i][j]為取完前i行數中 第i行為二進位制j狀態的最大值
比如dp[3][5]=20 表示取完前3行 第三行取了第一個和最後一個數(5的二進位制為101) 的最大值
則狀態轉移方程
dp[i][j]=max(dp[i-1][k]+curline); 其中(k & j ==0)
其中狀態k,j不是所有數都可以取 狀態二進位制表示中不能有連續的1 可以先預處理篩選出來
注意:此題測試資料中有n==0 輸出0
#include<stdio.h> #include<string.h> #define MAXN 200000 int dp[2][MAXN]; //滾動陣列 int stu[MAXN]; //表示所有合法狀態 二進位制中沒有連續的1 int bit[22]; //bit[i] 表示只取從右到左第i個數的狀態 如000100 只取第3個 int v[22]; //儲存每行讀入的數 int main() { int i,j,k,n,curi,prei,ans; int num=0,top=1<<20; bit[1]=1; for(i=2;i<=21;i++) bit[i]=bit[i-1]<<1; //下面預處理出所有合法狀態 for(i=0;i<top;i++) { for(j=1;bit[j]<=i;j++) { if((i & bit[j]) && (i & bit[j-1])) break; } if(bit[j]>i) stu[num++]=i; } //printf("%d\n%d\n",num,stu[num-1]); while(~scanf("%d",&n)) { memset(dp,0,sizeof(dp)); ans=0; top=1<<n; for(i=0;i<n;i++) { curi=i&1; prei=curi^1; for(j=0;j<n;j++) scanf("%d",v+j); for(j=1;stu[j]<top;j++) { int s=0,curmax=0; for(k=1;bit[k]<=stu[j];k++) { if(bit[k] & stu[j]) s+=v[n-k]; } for(k=0;stu[k]<top;k++) { if(!(stu[k] & stu[j])) curmax=curmax>dp[prei][k]?curmax:dp[prei][k]; } dp[curi][j]=curmax+s; if(ans<dp[curi][j]) ans=dp[curi][j]; //printf("dp[%d][%d]=%d\n",i,stu[j],dp[i&1][j]); } } printf("%d\n",ans); } return 0; }