2021河南省ccpc欢度佳节题解+赛后总结

本文介绍了一个基于掷骰子的游戏算法问题,玩家通过掷骰子积累糖果来占领地图上的格子,目标是在限定次数内占领尽可能多的格子。文章提供了一段C++代码实现,并详细解释了解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述

赛后总结:第一次距离金这么近,而且这道题几乎同类型的题,某acw网站算法基础课的 最短Hamilton路径,我还做过,但是当时没有想到两者一些相同的性质,还是练的少,明年省赛继续努力吧。

光棍节即将来临,小辣参加了某资本家的某游戏

即四根光棍在如图场景进行游戏,每个格子有一个数值 你可以掷若干次骰子,每次随机掷出 1 ~ 6 之间的整数值,加入糖果库存
如果某次掷骰子后你的糖果库存大于某个格子的数值,且这个格子与你占领的格子相邻,那么你可以选择占领这个格子,占领后库存清 0
我们称两个格子相邻当且仅当有一条边重合 默认一开始你位于左下方(即图中显示“我方”的位置),也就是说只有左下方的格子与你相邻
小辣用二十年单身换取了 n 次掷骰子的机会,你能告诉他最好情况下最多能占领几个格子吗

在这里插入图片描述

输入
第一行一个整数 T, 表示数据组数。对于每组数据:
第一行 17 个正整数,依次表示图中从左到右从上到下17个格子的数值,前四个表示第一行四个格子,第五到七表示第二行三个,以此类推。
第二行 1 个非负整数 n,表示掷骰子的次数
1≤T≤20, 保证所有数据 ≤109
输出
对于每组样例输出一行一个整数,表示最多能占领的格子数量
样例输入 Copy
2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
10
10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
100
样例输出 Copy
10
17

简单解题代码+思路注释

#include <bits/stdc++.h>

using namespace std;

int t,ar[20],sum,ans,cnt;
bool st[6][6];                                      /// 建图需要的数组

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};   /// 搜索上下左右四个方向

void init(int x)                                    /// 建图
{
    if(x==1) st[5][1] = true;
    else if(x==2) st[5][2] = true;
    else if(x==3) st[5][4] = true;
    else if(x==4) st[5][5] = true;
    else if(x==5) st[4][2] = true;
    else if(x==6) st[4][3] = true;
    else if(x==7) st[4][4] = true;  
    else if(x==8) st[3][2] = true;
    else if(x==9) st[3][3] = true;
    else if(x==10) st[3][4] = true;
    else if(x==11) st[2][2] = true; 
    else if(x==12) st[2][3] = true;
    else if(x==13) st[2][4] = true;
    else if(x==14) st[1][1] = true;
    else if(x==15) st[1][2] = true;
    else if(x==16) st[1][4] = true;
    else if(x==17) st[1][5] = true;
    
}
void dfs(int x,int y)                            /// 只搜一遍获取最大连通块数量
{
    st[x][y] = false; cnt++;
    for(int i=0; i<4; i++)
    {
        int dx_1 = x+dx[i],dy_1 = y+dy[i];
        if(dx_1<1||dx_1>5||dy_1<1||dy_1>5||!st[dx_1][dy_1]) continue;
        dfs(dx_1,dy_1);
    }
}

int main()
{
    cin>>t;
    while(t--)
    {
        ans = 0;                                    /// 记录能达到的最多的点
        for(int i=1; i<=17; i++) cin>>ar[i];        /// 存下每个方格需要的糖果数量
        cin>>sum;                                   /// 筛子个数
        for(int i=0; i< 1<<17; i++)                 /// 把所有情况不重复遍历一遍    
        {
            memset(st, 0, sizeof st);               /// 每次使用方法都要把数组重置一下
            int res = 0,sum1=0;                     /// sum1记录每一种方法所使用的糖果数
            for(int j=0; j<17; j++)                 /// 一共17个点所以要进行
            {
                if(i>>j&1) 
                {
                    res++;
                    init(j+1);
                    if(ar[j+1]%6!=0) sum1+=(ar[j+1]/6+1);   ///每次使用筛子的判定
                    else sum1+=(ar[j+1]/6);
                }
            }
            if(sum<sum1) continue;
            cnt = 0;
            if(!st[1][1]) continue;                         /// 起始点不存在的情况
            dfs(1,1);                                       /// 判断选中的几个点能否连通成一个连通块
            if(res == cnt) ans = max(ans,res);
            
        }
        cout<<ans<<"\n";
    }
    
    
    
    
    return 0;
}
### 2021 CCPC Guangzhou Onsite 题目解析 #### H题: Three Integers 该题目主要考察的是分类讨论以及合理运用倍数关系的能力。当输入数据中存在一个零时,需特别注意是否存在数值为1的情况。在这种情况下,为了防止被特定测试用例攻击(即所谓的“hack”),应适当调整倍数逻辑[^1]。 以下是实现此算法的一个可能代码示例: ```cpp #include <bits/stdc++.h> using namespace std; int main(){ int a,b,c; cin>>a>>b>>c; vector<int> nums={abs(a), abs(b), abs(c)}; sort(nums.begin(),nums.end()); long long res=LLONG_MAX; do{ if(nums[1]==0 && nums[2]!=0){ // 特殊情况处理 res=min(res,(long long)(nums[0]*nums[2])); } else { // 正常计算最小操作次数 long long temp=(nums[1]-nums[0]%nums[1])%nums[1]; temp += (nums[2]-nums[1]%nums[2])%nums[2]; res = min((long long)res,temp); } }while(next_permutation(nums.begin(),nums.end())); cout<<res<<"\n"; } ``` #### C题: Necklace 对于C题Necklace而言,其核心思路在于如何通过贪心策略来解决问题。具体来说,可以从第一个节点出发尝试尽可能地向右扩展路径长度;一旦遇到超出允许的最大长度`max_len`的情形,则将整个项链结构向左侧平移一定距离,从而最大化利用可用空间并减少资源浪费[^4]。 下面给出了一种基于上述思想的解决方案框架: ```cpp // 假设已知一些变量定义如 max_len, nodes 等... bool check(double mid){ double sum=0; for(auto &len:nodes){ if(sum+len<=mid){ sum+=len; } else{ return false; } } return true; } double binarySearch(){ double l=0,r=accumulate(nodes.begin(),nodes.end(),0.0); while(r-l>=EPS){ double mid=l+(r-l)/2; if(check(mid)){ r=mid-EPS; } else{ l=mid+EPS; } } return l; } ``` 以上两道典型题目展示了不同类型的解法技巧——前者依赖于细致入微的状态枚举与边界条件判断,后者则体现了经典优化理论中的动态规划与二分查找相结合的应用场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

侧耳倾听QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值