首页 > 其他分享 >ccpc威海 D-Sternhalma(状压DP,记忆化搜索)

ccpc威海 D-Sternhalma(状压DP,记忆化搜索)

时间:2022-12-01 14:56:48浏览次数:55  
标签:Sternhalma int 状压 ccpc cin 棋子 mp 移除 DP

题意

  • 给定六边形棋盘每个格子的分数,询问若干初始的棋子摆放
    方式,问按照规则移除棋子最多得多少分。
  • 移除棋子有两种方式,一种是直接移除一个棋子,不得分;
    另一种是用一个棋子跳过其相邻棋子,移除被跳过的棋子并
    且得分增加被移除棋子所在的格子的分数。

原题链接
解题思路
棋盘上的每个位置只有放与不放两种选择,故最终一共有\(2^{19}\)种状态。初态已知,那么我们可以用DP推出后面的所有状态,也可以用记忆化搜索。
代码细节较多,容易出错。

DP

#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 19) + 1;
//方向矩阵
const int d1[6][2] = {{0, 2}, {-1, 1}, {-1, -1}, {0, -2}, {1, -1}, {1, 1}};
const int d2[6][2] = {{0, 4}, {-2, 2}, {-2, -2}, {0, -4}, {2, -2}, {2, 2}};
//为每个点给定二维坐标
const int coor[19][2] = 
{
    {1, 3}, {1, 5}, {1, 7},
    {2 ,2}, {2 ,4}, {2 ,6}, {2, 8},
    {3, 1}, {3, 3}, {3, 5}, {3, 7}, {3, 9},
    {4, 2}, {4 ,4}, {4 ,6}, {4 ,8},
    {5, 3}, {5 ,5}, {5 ,7}
};
int s[6][10];//点的权值
int id[8][15];//每个区域的编号
int f[N];
//将字符串转化为十进制的状态
int trans(string &mp)
{
    int ans = 0;
    for (int i = 0; i < 19; ++i)
    {
        if (mp[i] == '#')
            ans += (1 << i);
    }
    return ans;
}
int count(int x)
{
    int ans = 0;
    for (int i = 0; i < 19; ++i)
    {
        if (x & 1 << i)
            ++ans;
    }
    return ans;
}
vector<int> b;
void ini()
{
    for (int i = 0; i < (1 << 19); ++i)
        b.push_back(i);
    //排序,从小状态推大状态
    sort(b.begin(), b.end(), [](int a, int b)
    {
        return count(a) < count(b);
    });
    for (int i = 1; i < (1 << 19); ++i)
    {   
        int state = b[i];
        for (int j = 0; j < 19; ++j)
        {
            if (state & (1 << j))
            {
                int x = coor[j][0], y = coor[j][1];
                f[state] = max(f[state], f[state - (1 << j)]);
                for (int k = 0; k < 6; ++k)
                {
                    int x1 = x + d1[k][0], y1 = y + d1[k][1];
                    int x2 = x + d2[k][0], y2 = y + d2[k][1];
                    if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0)
                        continue;
                    if (id[x1][y1] == -1 || id[x2][y2] == -1)
                        continue;
                    //注意&与==的优先级
                    if ((state & 1 << id[x1][y1]) == 0 || (state & 1 << id[x2][y2]) == 1)
                        continue;
                    f[state] = max(f[state], f[state ^ (1 << id[x][y]) ^ (1 << id[x1][y1]) ^ (1 << id[x2][y2])] + s[x1][y1]);
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    memset(id, -1, sizeof(id));
    memset(f, -0x3f, sizeof(f));
    f[0] = 0;
    for (int i = 0; i < 19; ++i)
    {
        int x = coor[i][0], y = coor[i][1];
        id[x][y] = i;
        cin >> s[x][y];
    }
    ini();
    int n;
    cin >> n;
    while (n--)
    {
        string mp, t;
        for (int i = 0; i < 5; ++i)
            cin >> t, mp += t;
        cout << f[trans(mp)] << endl;;
    }
}

记忆化搜索

#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 19) + 1;
const int d1[6][2] = {{0, 2}, {-1, 1}, {-1, -1}, {0, -2}, {1, -1}, {1, 1}};
const int d2[6][2] = {{0, 4}, {-2, 2}, {-2, -2}, {0, -4}, {2, -2}, {2, 2}};
 
const int coor[19][2] = 
{
    {1, 3}, {1, 5}, {1, 7},
    {2 ,2}, {2 ,4}, {2 ,6}, {2, 8},
    {3, 1}, {3, 3}, {3, 5}, {3, 7}, {3, 9},
    {4, 2}, {4 ,4}, {4 ,6}, {4 ,8},
    {5, 3}, {5 ,5}, {5 ,7}
};
int s[6][10];//点的权值
int id[8][15];//每个区域的编号
int f[N];
int trans(string &mp)
{
    int ans = 0;
    for (int i = 0; i < 19; ++i)
    {
        if (mp[i] == '#')
            ans += (1 << i);
    }
    return ans;
}
int dfs(int state)
{
    if (f[state] != int(0xc1c1c1c1))
        return f[state];
    int &val = f[state];
    int grid[8][15] = {0};
    for (int i = 0; i < 19; ++i)
    {
        if (state & 1 << i)
        {
            int x = coor[i][0], y = coor[i][1];
            int n_state = state & ~(1 << i);
            grid[x][y] = 1;
            val = max(val, dfs(n_state));
        }        
    }
    
    for (int i = 0; i < 19; ++i)
    {
        if (state & 1 << i)
        {
            int x = coor[i][0], y = coor[i][1];
            for (int j = 0; j < 6; ++j)
            {
                int x1 = x + d1[j][0], y1 = y + d1[j][1];
                int x2 = x + d2[j][0], y2 = y + d2[j][1];
                if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0)
                    continue;
                if (!~id[x1][y1] || !~id[x2][y2])
                    continue;
                if (!grid[x1][y1] || grid[x2][y2])
                    continue;
                int n_state = state;
                n_state &= ~(1 << i);
                n_state &= ~(1 << id[x1][y1]);
                n_state |= (1 << id[x2][y2]);
                val = max(val, dfs(n_state) + s[x1][y1]);
            }
        }
    }
    return val;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    memset(id, -1, sizeof(id));
    memset(f, -0x3f, sizeof(f));
    f[0] = 0;
    for (int i = 0; i < 19; ++i)
    {
        int x = coor[i][0], y = coor[i][1];
        id[x][y] = i;
        cin >> s[x][y];
    }
    int n;
    cin >> n;
    while (n--)
    {
        string mp, t;
        for (int i = 0; i < 5; ++i)
            cin >> t, mp += t;
        cout << dfs(trans(mp)) << endl;;
    }
}

标签:Sternhalma,int,状压,ccpc,cin,棋子,mp,移除,DP
From: https://www.cnblogs.com/hetailang/p/16941388.html

相关文章

  • 状压DP入门
    状态压缩DP思想简述:DP的实质是在状态空间中的遍历,在部分题目中,DP在状态空间的轮廓需要我们很清晰的刻画出来,所以我们在DP过程中需要维护一个集合,来保存这个轮廓的详细信息......
  • 2022ccpc绵阳(2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite)
    链接:https://codeforces.com/gym/104065A#include"bits/stdc++.h"usingnamespacestd;usingi64=longlong;constexprintN=2E5;boolvis[N+10][11][11......
  • CCPC 广州站打星记
    Day-1老师给我们报了CCPC广州站的线上赛,第一次参加正式ACM赛,多少还是有些激动。(那个THUPC算不了啥啦)我被选成GF2队的队长,队员是wcj和lgj(为什么不是captain......
  • 2018ccpc女生赛A题口算训练
    #include<bits/stdc++.h>using namespace std;#define ios() ios::sync_with_stdio(false);cin.tie(0);/*我们对输入的每一个数字分解质因数,分解过程中把下标存入......
  • 【状压DP】哈密顿回路问题
    【状压DP】哈密顿回路问题lzq同学在我准备午睡的时候发了一道蓝桥杯的题目给我,是哈密顿回路的。第一次看的时候是想DFS+双向搜索优化减小搜索树规模,然后写烂了(如果有大佬用......
  • ABC 214E Chain Contestant(状压计数)
    ABC214EChainContestant(状压计数)ChainContestant​ 现在有十个比赛类型,从现在开始要进行N场比赛。N场比赛的类型通过一个字符串S给出,在S串中选择一个子序列S',满足下......
  • The 2021 CCPC Guilin Onsite (XXII Open Cup, Grand Prix of EDG
    https://codeforces.com/gym/103409/problem/BB.APlusBProblem—————数据结构(set)题意给你两个n位的数a,b(有前导零),c是a+b的结果(最高位的进位已省略)q次询......
  • 2020CCPC长春(待补)
    D.MeaninglessSequence分析:我居然找规律做出来了!!!!发现长度为k的一系列数就是长度为k-1的一系列复制一遍加上k-1的一系列乘c再复制一遍这样前缀和就能处理出来......
  • 捆绑包装——状压 dp
    状压dp,顾名思义,就是把一个状态压缩成一个整数的dp。状态.zip状压dp都有个特点:$n$很小!暴力辗标算而时间复杂度都是$O(k2^n)$什么的……($k$为其他部分复杂......
  • 秦皇岛2020CCPC补题
    秦皇岛2020CCPCA,E,F,G,I,KA.AGreetingfromQinhuangdao知识点:简单题复杂度:\(O(logn)\)#include<bits/stdc++.h>usingnamespacestd;#definerep(i,l,r)for(in......