hdu 1565格子取数(状圧dp入門)
5679 ワード
グリッド数(1)
Problem Descriptionはn*nの格子の碁盤をあげて、各格子の中に非負の数があります.任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Inputは複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Outputは、各テストインスタンスについて、取得可能な最大和を出力する
Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
解析:この問題は状態圧縮dpの入門問題である.状態圧縮とは,状態(0はそのビットを取らず,1はそのビットを表す)をバイナリで表し,それを10進数の数値に変換することである.例えば、状態「101」は、0位、2位、1位を取らず、10進数に移行すると状態5となる.したがって、各10進数は一意の状態を表すことができます.
この問題に対して、まず、上下隣接を考慮しなければ、各行の取法または状態は相対的に独立して完全に同じであるため、1行中のすべての可能な取法または状態(隣接する1が存在しない)を挙げることを考慮する.以下、上下隣接の場合を処理する.i行目のすべての可能な状態を列挙し、i行目のすべての可能な状態を列挙し、2つの相があり、結果が0であれば、2つの状態の間に上下隣接が存在しないことを説明し、この取り方は可能であり、逆である.
ACコード
#include
#define ll long long
using namespace std;
int tai[20000];//
ll dp[21][20000];//dp[i][j] i j
ll a[21][21];
int n;
ll cal(int row,int sta)
{
int col=0;
ll sum=0;
while(sta)
{
int x=1<1);
if(sta&x)
{
sta-=x;
sum+=a[row][col];
}
col++;
}
return sum;
}
void gnt(int pos,int cnt,int last)//pos ,cnt ,last
{
if(pos==0)
{
tai[num++]=cnt;
return ;
}
if(last)
gnt(pos-1,cnt,0);
else
{
gnt(pos-1,cnt+(1<1)),1);
gnt(pos-1,cnt,0);
}
}
void init(int n)
{
num=0;
memset(dp,0,sizeof(dp));
gnt(n-1,1<1),1);//1 ,0
gnt(n-1,0,0);
}
int main()
{
while(scanf("%d",&n)==1)
{
for(int i=0; ifor(int j=0; jscanf("%lld",&a[i][j]);
if(n==0)
{
printf("0
");
continue;
}
init(n);
for(int i=0; i0][i]=cal(0,tai[i]);
for(int i=1;ifor(int j=0;j// i
{
ll tmp=cal(i,tai[j]);
for(int k=0;k// i-1
{
if(tai[j]&tai[k]) continue;//
dp[i][j]=max(dp[i-1][k]+tmp, dp[i][j]);
}
}
}
ll ans = 0;
for(int j=0;j1][j], ans);
printf("%lld
",ans);
}
return 0;
}