题目链接
题意
给一个矩阵求权值最大连通块
思路
轮廓线,考虑轮廓线上的连通种类数即可,连通种类数用最小表示法处理。当连通种类只有一种时可以更新答案。
本代码为了方便使用 unordered_map
实现,不能直接取max,如果一个状态第一次出现直接赋值即可,因为当前状态答案可能是负数。
代码
#include <bits/stdc++.h>
using namespace std;
unordered_map<int,int> dp[2];
int n, a[15][15], bit[15];
int ans;
int getsta(int sta, int w){
int fq[10], tot = 0, s = 0;
memset(fq,0,sizeof(fq));
for(int i = 1; i <= n; ++i) {
int x = (sta>>bit[i])&7;
if(!x) continue;
if(!fq[x]) fq[x] = ++tot;
s += fq[x]*(1<<bit[i]);
}
if(tot == 1) ans = max(ans,w);
return s;
}
void ins(int sta, int w, int cur) {
sta = getsta(sta,w);
if(dp[cur].find(sta) == dp[cur].end()) {
dp[cur][sta] = w;
return;
}
dp[cur][sta] = max(dp[cur][sta],w);
}
void solve() {
int cur = 0;
dp[cur].clear();
dp[0][0] = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
cur ^= 1;
dp[cur].clear();
for(auto p : dp[cur^1]) { // 每种情况上面半段不选,下面半段是选
int sta = p.first;
int w = p.second;
int d = (sta>>bit[j])&7;
int r = (sta>>bit[j-1])&7;
if(!r && !d) {
ins(sta,w,cur);
ins(sta+7*(1<<bit[j]), w+a[i][j], cur);
}
else if(r && !d) {
ins(sta,w,cur);
ins(sta+r*(1<<bit[j]), w+a[i][j], cur);
}
else if(!r && d) {
int flag = 0;
for(int k = 1; k <= n; ++k) if(((sta>>bit[k])&7) == d) ++flag;
if(flag > 1) ins(sta-d*(1<<bit[j]),w,cur);
ins(sta,w+a[i][j],cur);
}
else if(r && d) {
int flag = 0;
for(int k = 1; k <= n; ++k) if(((sta>>bit[k])&7) == d) ++flag;
if(flag > 1) ins(sta-d*(1<<bit[j]),w,cur);
for(int k = 1; k <= n; ++k) { // merge
if(((sta>>bit[k])&7) == d) sta = sta+(r-d)*(1<<bit[k]);
}
ins(sta,w+a[i][j],cur);
}
}
}
}
printf("%d\n",ans);
}
int main() {
scanf("%d",&n);
ans = -1e9;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
scanf("%d",&a[i][j]);
ans = max(ans, a[i][j]);
}
}
for(int i = 1; i <= 10; ++i) bit[i] = i*3;
solve();
return 0;
}