[51nod1411] 矩阵取数问题 V3

题目大意

给定一个m行n列的矩阵,你可以从任意位置开始取数,到达任意位置都可以结束,每次可以走到的数是当前这个数上下左右的邻居之一,唯一的限制是每个位置只能经过一次,也就是说你的路径不自交。所经过的数的总作为你的得分,求最大的得分。

n,m≤10
整数范围[-10000000,10000000]

分析

求一条路径、上下左右走的矩阵,很容易想到插头DP。
设f[i][j][S]表示决策到(i,j),插头状态为S的答案。现在看状态怎样存。
首先无插头表示为0,联通的插头看成左右括号,记为1、2,由于是一条不自交的路径,括号序是没问题的。路径会有两个端点,这个端点伸出来的插头不与其它插头配对(除非在当前决策的格子与其它插头相连),所以还要记录独立的插头,记为3
这样就可以4进制来表示了。

然后就可以分类讨论了!
注意边界!!!

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=209189;

typedef long long LL;

int n,m,p,q,cnt[1<<22],ans;

int map[11][11];

struct node
{
    int H[maxn],tot,st[maxn];
    LL s[maxn];
    void init()
    {
        memset(H,255,sizeof(H));
        tot=0;
    }
    void add(int S,int v)
    {
        int i=S%maxn;
        for (;H[i]>=0 && st[H[i]]!=S;i=(i+1)%maxn);
        if (H[i]<0)
        {
            st[tot]=S; s[tot]=v; H[i]=tot++;
        }else if (v>s[H[i]]) s[H[i]]=v;
    }
}f[2];

int Get(int s,int w)
{
    return (s>>(w<<1))&3;
}

void Set(int &s,int w,int v)
{
    s^=Get(s,w)<<(w<<1);
    s^=v<<(w<<1);
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++) for (int j=0;j<m;j++) scanf("%d",&map[i][j]);
    for (int i=0;i<(1<<(m*2+2));i++)
        for (int j=0;j<m;j++) cnt[i]+=(Get(i,j)==3);
    p=0; q=1;
    f[p].init();
    f[p].add(0,0);
    ans=-10000001;
    for (int i=0;i<n;i++) for (int j=0;j<m;j++) ans=max(ans,map[i][j]);
    for (int i=0;i<n;i++)
    {
        for (int j=0;j<m;j++,p^=
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值