HDU-1565格子取数(1)(DP)
2062 ワード
Description
n*nの格子の碁盤をあげて、各格子の中に非負の数があります.
任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
Sample Output
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[i][j] i j , , , ,
,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1<<21;
int status[maxn], n, cnt;
int dp[2][maxn];
int ans, g[22][22];
void init() {
cnt = 0;
for (int i = 0; i < (1<<20); i++) {
if (i & (i << 1))
continue;
else status[cnt++] = i;
}
}
int main() {
init();
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &g[i][j]);
if (n == 0) {
printf("0
");
continue;
}
int tot = 1 << n;
ans = 0;
for (int i = 0; status[i] < tot; i++) {
dp[0][i] = 0;
for (int j = 0; j < n; j++)
if (status[i] & (1<<j))
dp[0][i] += g[0][j];
ans = max(ans, dp[0][i]);
}
int cur = 0;
for (int i = 1; i < n; i++) {
cur ^= 1;
for (int j = 0; status[j] < tot; j++) {
int tmp = 0;
dp[cur][j] = 0;
for (int k = 0; k < n; k++)
if (status[j] & (1 << k))
tmp += g[i][k];
for (int k = 0; status[k] < tot; k++)
if ((status[j] & status[k]) == 0)
dp[cur][j] = max(dp[cur][j], dp[cur^1][k]+tmp);
ans = max(ans, dp[cur][j]);
}
}
printf("%d
", ans);
}
return 0;
}