【poj 2286】The Rotation Game 题意&题解&代码(C++)

本文介绍使用IDA*搜索算法解决井字棋盘问题,目标是最少步骤使中心区域数字一致。通过优化搜索策略,避免无效操作提高效率。

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

题目链接:
http://poj.org/problem?id=2286
题意:
刚开始给出如图所示的一个井字形棋盘,每个棋盘上放有一个数,这个数一定是1,2,3中的一个,按图所示给列标号,现在有8种操作,每种操作分别为ABCDEFGH对应图中标号,每次操作相当于将这一列往标号的方向滚动一格,题上图示为先操作A,再操作C,问最少几次操作使得中心的8个格子数字相同,输出最后中心的数字,输出操作方式,不用操作则输出 No moves needed
题解:
IDA*搜索,这道题的估价比较直白,直接找中心八个数中的数量最多的数出现的次数 pri ,然后若当前步数 dep+8 - pri > ans 则不继续往下搜。

注意刚开始给棋盘标号,一定要细心,我就因为一个数字标错调了半个小时,QAQ。

还有一个很大的优化点,那就是按题上标号时,如果上一步操作了A,那么这步一定不要操作G,因为会抵消上步操作的作用,而刚开始我想着用sum[i]表示操作i的总次数,操作i一定不会超过7次,这样想着去优化,结果优化效果并不明显直接TLE。

代码:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int tt,s[25],cnt[4],ans,path[40];
int check(int *w)
{
    if (w[7]==w[8]&&w[8]==w[9]&&w[9]==w[13]&&w[13]==w[12])
    if (w[12]==w[16]&&w[16]==w[17]&&w[17]==w[18])
    {
        tt=w[9];
        return 1;
    }
    return 0;
}
//此处标号一定小心!!!!
int pan[8][7]={ {1, 3, 7,12,16,21,23},   //A
        {2, 4, 9,13,18,22,24},     //B
        {11,10,9, 8, 7, 6, 5},     //C  
        {20,19,18,17,16,15,14},    //D
        {24,22,18,13, 9, 4, 2},    //E
        {23,21,16,12, 7, 3, 1},    //F
        {14,15,16,17,18,19,20},    //G
        {5, 6, 7, 8, 9, 10,11}};       //H
int fan[8]={5,4,7,6,1,0,3,2};
int num[8]={7,7,7,7,7,7,7,7};
void rotate(int x,int *k)
{
    int tmp=k[pan[x][0]];
    for (int i=0;i<6;i++)
    k[pan[x][i]]=k[pan[x][i+1]];
    k[pan[x][6]]=tmp;
}
int dfs(int dep,int *now,int *mov,int pre)
{
    if (check(now)) return 1;
    cnt[1]=0;cnt[2]=0;cnt[3]=0;
    cnt[now[7]]++;cnt[now[8]]++;cnt[now[9]]++;cnt[now[13]]++;
    cnt[now[12]]++;cnt[now[16]]++;cnt[now[17]]++;cnt[now[18]]++;
    int pri=max(cnt[3],max(cnt[1],cnt[2]));
    if (dep+8-pri>ans) 
    return 0;

    for (int i=0;i<8;i++)
    if (fan[i]!=pre)
    {
        rotate(i,now);
        mov[dep+1]=i;
        if (dfs(dep+1,now,mov,i))return 1;
        rotate(fan[i],now);
    }
    return 0;
}
int main()
{
    while(scanf("%d",&s[1]))
    {
        if (s[1]==0) return 0;
        for (int i=2;i<=24;i++)
        scanf("%d",&s[i]);
        if (check(s)) 
        {
            printf("No moves needed\n");
            printf("%d\n",s[9]);
            continue;
        }
        for (int i=1;i<=29;i++)
        {
            ans=i;
            int hh[25];
            for (int i=1;i<=24;i++) hh[i]=s[i];
            if (dfs(0,hh,path,-1)) break;
        }
        for (int i=1;i<=ans;i++)
        {
            char c=path[i]+'A';
            printf("%c",c);
        }
        printf("\n");
        printf("%d\n",tt);
    }
}
### 关于 POJ 2286 的解决方案 POJ 平台上的题目编号通常对应特定算法或数据结构的应用场景。对于 POJ 2286,虽然未提供具体描述,但从其编号范围推测可能涉及动态规划、贪心策略或其他经典算法。 #### 动态规划方法 如果该问题是关于寻找友好数对的数量,则可以采用如下思路解决: 定义两个数组 `sum_divisors` 和 `friend_pairs` 来分别存储每个数的因子和以及已找到的友好数对数量。通过遍历小于给定上限的所有整数 \( n \),计算它们的因子之和并验证是否存在对应的友好数关系[^2]。 以下是实现这一逻辑的一个 Python 示例代码: ```python def calculate_friend_numbers(limit): sum_divisors = [0] * (limit + 1) # 计算所有数的因子和 for i in range(1, limit + 1): for j in range(i * 2, limit + 1, i): sum_divisors[j] += i friend_count = 0 seen_friends = set() # 验证每一对是否构成友好数字 for num in range(1, limit + 1): partner = sum_divisors[num] if ( partner &lt; limit and partner != num and sum_divisors[partner] == num and (num, partner) not in seen_friends ): friend_count += 1 seen_friends.add((num, partner)) seen_friends.add((partner, num)) # 对称处理 return friend_count print(calculate_friend_numbers(10000)) # 输出小于一万的友好数量 ``` 上述代码实现了基于因子求和的方法来查找指定范围内所有的友好数对,并统计总数。 #### 数据结构优化 如果是类似于 **Balanced Lineup** 这样的区间最值查询问题,则需考虑高效的数据结构支持快速访问操作。例如使用线段树或者稀疏表(Sparse Table),可以在 O(log N) 或更低的时间复杂度下完成多次询问响应[^3]。 假设输入是一系列牛的高度序列,目标是最小化任意连续子列中的最大高度差。那么预处理阶段构建辅助索引之后,在每次请求到来时只需执行常数级运算即可得出结果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值