hdu 1565 方格取數(1)【狀壓dp】
方格取數(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7585 Accepted Submission(s): 2861
Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。
從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。
Input 包括多個測試例項,每個測試例項包括一個整數n 和n*n個非負數(n<=20)
Output 對於每個測試例項,輸出可能取得的最大的和 Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
Author ailyanlu
Source
思路:
建立dp【i】【j】二維陣列,表示第i行狀態為j的最大取值,不難推出其狀態轉移方程:dp【i】【j】=max(dp【i】【j】,dp【i-1】【k】+sum),其中sum表示j狀態下的取值。
首先我們要了解二進位制的表示方法,e.g,當j==5的時候,表示101,也就是在表示取第一個和第三個位子上的數,第二個位子上的數不取。
然後我們可以通過列舉的方法列舉一行裡邊可以選取的方案,其實就是要把帶有相鄰的1的情況拋去。那麼我們可以使用位運算來解決這個問題;那麼具體要如何實現呢?對於與運算(&)計算方式為同位為1結果為1,其餘都是0,我們不妨這樣來判斷一個方案能否有相鄰的1存在,例如現在狀態為j:
j&(j<<1),假如現在j==7
1 1 1&1 1 1 0=0110,
又假如現在j==5
1 0 1&1 0 1 0 =0;
不難發現如果值不為0,那麼就表示這種情況有相鄰的1,否則沒有。對於這部分的程式碼實現:
然後就是對於dp部分的處理,我們列舉每一行的狀態j(j屬於陣列q),算出這一行這種狀態j下的取值和,使得dp【i】【j】=sum。再列舉上一行的狀態k,如果j狀態和k狀態沒有上下相鄰的1,那麼就有:dp【i】【j】=max(dp【i】【j】,dp【i-1】【k】+sum)對於j狀態和k狀態能否有相鄰的1.直接&即可。(剛剛把這種操作已經詳解,這裡不再囉嗦)。</pre><pre name="code" class="cpp"> for(int i=0; i<end; i++) { if((i&(i<<1))==0) { q[cont++]=i; //printf("%d\n",i); } }
對於這部分的程式碼實現:
for(int i=0; i<n; i++)
{
for(int j=0; j<cont; j++)
{
int sum=0;
for(int k=0; k<n; k++)
{
if((q[j]&(1<<k))!=0)
{
sum+=a[i][k];
}
}
dp[i][j]=sum;
if(i>=1)
for(int k=0; k<cont; k++)
{
if((q[j]&q[k])==0)
{
dp[i][j]=max(dp[i][j],dp[i-1][k]+sum);
}
}
}
}
最後在第n-1行裡邊列舉一遍維護最大值即可。
另外注意一個問題,開1<<20的陣列會MLE,因為我們直接枚舉出cont個可以的方案(沒有相鄰1)其方案數不會達到這麼大,所以我們陣列也就不用開辣麼大。
AC程式碼:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[25][25];
int dp[21][200000];
int q[200000];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
scanf("%d",&a[i][j]);
}
}
int cont=0;
int end=1<<n;
for(int i=0; i<end; i++)
{
if((i&(i<<1))==0)
{
q[cont++]=i;
//printf("%d\n",i);
}
}
// printf("%d\n",cont);
for(int i=0; i<n; i++)
{
for(int j=0; j<cont; j++)
{
int sum=0;
for(int k=0; k<n; k++)
{
if((q[j]&(1<<k))!=0)
{
sum+=a[i][k];
}
}
dp[i][j]=sum;
if(i>=1)
for(int k=0; k<cont; k++)
{
if((q[j]&q[k])==0)
{
dp[i][j]=max(dp[i][j],dp[i-1][k]+sum);
}
}
}
}
int output=0;
for(int i=0; i<cont; i++)
{
output=max(output,dp[n-1][i]);
}
printf("%d\n",output);
}
}
相關推薦
hdu 1565 方格取數(1)【狀壓dp】
方格取數(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7585 Accepted Subm
hdu 1565 方格取數(狀壓dp)
給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測試例項包括一個整數n 和n*n個非負數(n<=20)
HDU 1565 方格取數(1) (狀壓DP)
http://acm.hdu.edu.cn/showproblem.php?pid=1565 #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring>
HDU 1565 方格取數(1) (狀態壓縮DP入門題 2)(待更新)
Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。Input 包括多個測試例項,每個測試例項包括一個整數n 和n*n
HDU 1565 方格取數(1)(最大獨立點集)
題目地址 題意:中文。 思路:我是實在想不懂這類題目為什麼可以轉化為網路流來寫,於是我看了好多題解。然後發現因為相鄰的兩個點是不能同時選的,然後這樣就劃分成了兩類點,用奇偶建點的方法,可以很明白的寫出這個模型,因為相鄰兩點的橫縱座標加起來一定是一奇一偶的。然
hdu 1565 方格取數(1)(狀態壓縮DP)
終於可以寫題解了。因為一個細節上的失誤,讓我重新修改的程式碼一直通不過測試,鬱悶。 程式碼毫無參考價值,剛學的狀態壓縮DP,程式碼寫得很難看。 #include<stdio.h> #inc
HDU 1565 方格取數(1)(插頭DP||狀態壓縮)
Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測試例項包括一
hdu 1565 方格取數(1)(最小割)
方格取數(1) Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測試例項
HDU 1565 - 方格取數(1) - [狀壓DP][網絡流 - 最大點權獨立集和最小點權覆蓋集]
printf 一個 cnblogs ret com bool limit .net amp 題目鏈接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory
HDU 1565 方格取數(1)
can getchar class target 方格取數 set ems n-k ++ 鏈接 思路 狀壓dp,dp[i][j]:表示到第i行,當前狀態為s的最大值。預處理在每一行選的時候可能的狀態,及這個狀態的價值。 轉移方程:dp[i][j] = max(
hdu 2167 方格取數 【狀壓dp】(經典)
取出 fff ack 分析 題目 經典 gets bsp ets <題目鏈接> 題目大意: 給出一些數字組成的n*n階矩陣,這些數字都在[10,99]內,並且這個矩陣的 3<=n<=15,從這個矩陣中隨機取出一些數字,在取完某個數字後,該數字周圍8
HDU 1565 方格取數(1)(最大點權獨立集)
題目大意:給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 解題思路:最大點權獨立集,關鍵是怎麼建圖了,我們可以採用染色的思想對這張圖
HDU 1565 方格取數(1)(狀態壓縮DP)
挺簡單的一個狀壓DP,因為一點小失誤搞了好久。。 先按最大值跑一遍getState可以知道一行可以有多少種狀態,就是MAX_K。狀態轉移方程:dp[s][i] = max(dp[s][i], dp[j][i - 1] + getSum(state[s], i)),dp[s
hdu 1565 方格取數(1)【最大流】
程式碼: #include <iostream> #include <algorithm> #include <set> #include <map> #include <string.h> #i
hdu 1565 方格取數(1) 位壓縮動態規劃
hdoj 1565 dp 方格取數(1) Time Limit: 1000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1162
HDU 1565 方格取數(1) 狀態壓縮DP
題目大意: 從n*n的矩陣中取出一些數使得這些數互不相鄰,問最大和為多少 大致思路: 明顯的狀態壓縮DP,每兩行之間的狀態轉移,這裡受到記憶體限制只開兩個陣列來表示當先行和下一行來進行轉移,原本想用vector來記錄那兩個狀態之間可以轉換的,但是受到記憶體限制還是用時間換
hdu 1565 方格取數(2)(網絡流之最大點權獨立集)
href aps flow bit 明顯 log sum dir 一個 題目鏈接:hdu 1565 方格取數(2) 題意: 有一個n*m的方格,每個方格有一個數,現在讓你選一些數。使得和最大。 選的數不能有相鄰的。 題解: 我們知道對於普通二分圖來說,最大獨立點集 + 最小
HDU 1565 方格取數 題解
【題目】: Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測
【bzoj2734】集合選數(有點思維的狀壓dp)
題目傳送門:bzoj2734 這題一個月前看的時候沒什麼頭緒。現在一看,其實超簡單。 我們對於每個在$ [1,n] $範圍內的,沒有因數2和3的數$ d $,將它的倍數$ 2^a 3^b d $一起處理。因為每個數$ d $之間沒有2和3作為公因數,所以統計時互不影響。 對於$ d $的
web前端開發專案中可能遇到的細節性問題(1)【position,padding+margin】
1.區別a和b—— a.position:absolute; b.position:relative; ——position:absolute;表示絕對定位, (1)其一般要設定高度跟居左的畫