格子取数(HDU-1565)(状圧DP)
1682 ワード
n*nの格子の碁盤をあげて、各格子の中に非負の数があります.任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
Sample Output
中国語の問題なので、問題の意味はもう説明しません.
考え方:この問題は、DPを押す問題です.まず、列ごとにバイナリ状態にすることができます.それから、状態が合法かどうかを判断するだけでいいです.
ACコード:
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
中国語の問題なので、問題の意味はもう説明しません.
考え方:この問題は、DPを押す問題です.まず、列ごとにバイナリ状態にすることができます.それから、状態が合法かどうかを判断するだけでいいです.
ACコード:
#include
typedef long long ll;
const int maxx=10010;
const int inf=0x3f3f3f3f;
using namespace std;
int a[19][1<<17];
int f[19][1<<17];
int b[maxx];
int calc(int i,int x)
{
int cnt=1,ans=0;
while(x)
{
if(x&1)
ans+=a[i][cnt];
x/=2;
cnt++;
}
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int cnt=0,ans=0;
for(int i=0; i >1))==0)
b[++cnt]=i;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d",&a[i][j]);
memset(f,0,sizeof(f));
for(int i=1; i<=n; i++)
{
for(int k=1; k<=cnt; k++)
{
int val=calc(i,b[k]);
for(int j=1; j<=cnt; j++)
{
if((b[j]&b[k])==0)
{
f[i][k]=max(f[i][k],f[i-1][j]+val);
}
}
}
}
for(int j=1; j<=cnt; j++)
ans=max(ans,f[n][j]);
printf("%d
",ans);
}
return 0;
}