题目:http://acm.hdu.edu.cn/showproblem.php?pid=1565
题意:自己念
分析:有了上一题的基础,这题的状态方程也好想:dp[i][s]表示第i行第s个状态取得的最大值。
可以预处理出每一行每一种状态所能获得的值,方程就是dp[i][j] = max(dp[i][j],dp[i-1][k]+sum[i][j]);
要注意的就是判断相邻的情况:两个状态,如果a&b!=0则表示它们有相重叠的区域。
#include <bits/stdc++.h> using namespace std; void read(){ #ifndef ONLINE_JUDGE freopen("D:\fengyu\Jiang_C\.vscode\in.txt","r",stdin); freopen("D:\fengyu\Jiang_C\.vscode\out.txt","w",stdout); #endif } #define clr(a) memset(a,0,sizeof(a)) #define ll long long ll a[25][25],s[20005]; ll dp[25][20005]; ll sum[25][20005]; int main() { read(); int n; int num = 0; for (int i = 1; i< 1<<20; i++) { if(i&i<<1) continue; s[num++]=i; } while (cin >> n) { clr(dp); clr(sum); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> a[i][j]; } } for (int i = 1; i <= n; i++) { for (int j = 0; s[j] < 1<<n; j++) { int t = s[j]; for (int k = 1; k <= n; k++) { if(t&1) sum[i][j]+=a[i][k]; t>>=1; } } } for (int j = 0; s[j] < 1<<n; j++) { dp[1][j] = sum[1][j]; } for (int i = 2; i <= n; i++) { for(int j = 0; s[j] < 1<<n; j++) { for(int k = 0; s[k] < 1<<n; k++) { if (s[k] & s[j]) continue; dp[i][j] = max(dp[i][j],dp[i-1][k]+sum[i][j]); } } } ll ans = 0; for (int j = 0; s[j] < 1<<n; j++) { ans = max(ans,dp[n][j]); } cout << ans << endl; } return 0; }