HDU 1565 方格取数(1) (状态压缩DP)
ACM
题目地址:
HDU 1565 方格取数(1)
题意:
中文。
分析:
dp[i][j]表示前i行状态j的最优解。
先预处理出符合条件的数,17000+个(n在20以内)。
不过感觉复杂度挺高的会T,但是却能A。
这题的正解应该是最小割,回头补下。
代码:
/*
* Author: illuz <iilluzen[at]gmail.com>
* File: 1565_dp.cpp
* Create Date: 2014-09-19 23:30:19
* Descripton: dp
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
typedef long long ll;
const int N = 1<<21;
int n, st[N], stn;
int dp[2][N];
int ans, g[25][25];
void pre() {
repf (i, 0, (1<<20)) {
if (i & (i<<1))
continue;
else
st[stn++] = i;
}
}
void solve() {
if (n == 0) {
cout << 0 << endl;
return;
}
int tot = 1<<n;
ans = 0;
// first line
for (int i = 0; st[i] < tot; i++) {
dp[0][i] = 0;
repf (j, 0, n - 1)
if (st[i]&(1<<j))
dp[0][i] += g[0][j];
ans = max(ans, dp[0][i]);
}
// 2~n line
repf (i, 1, n - 1) {
for (int j = 0; st[j] < tot; j++) {
int tmp = 0;
dp[i&1][j] = 0;
// can get tmp value
repf (k, 0, n - 1) {
if (st[j]&(1<<k))
tmp += g[i][k];
}
for (int k = 0; st[k] < tot; k++) {
if (!(st[j]&st[k]))
dp[i&1][j] = max(dp[i&1][j], tmp + dp[!(i&1)][k]);
}
ans = max(ans, dp[i&1][j]);
}
}
cout << ans << endl;
return;
}
int main() {
ios_base::sync_with_stdio(0);
pre();
while (cin >> n) {
repf (i, 0, n - 1) repf (j, 0, n - 1)
cin >> g[i][j];
solve();
}
return 0;
}