洛谷 P3886 [JLOI2009]神秘的生物(插头DP)

题目链接
题意

给一个矩阵求权值最大连通块

思路

轮廓线,考虑轮廓线上的连通种类数即可,连通种类数用最小表示法处理。当连通种类只有一种时可以更新答案。

本代码为了方便使用 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值