C++ アルゴリズム入門トレーニング - 九公並べ替え、ラッキーナンバー (コード付き)

例 - 九公の再配置

トピックの背景

        たとえば、下の最初の写真の九公グリッドには、1 から 8 までの数字カードがあり、もう 1 つの空のグリッドがあります。空きスペースに隣接するグリッド内のカードは、空きスペースに移動できます。数回動かすと、2 番目の図に示す状況が形成されます。

        最初の写真の状況を 12345678 として記録します。

        2 番目の写真の状況を次のように記録します: 123.46758

        どうやら数字は上から下、左から右に記録され、スペースはピリオドとして記録されます。

        このトピックのタスクは、九功の初期状態と最終状態を知り、少なくとも何段階まで到達できるかを調べることです。何歩進んでも到達できない場合は-1を出力します。

入力フォーマット

        入力の最初の行には九功の初期状態が含まれ、二行目には九功の最終状態が含まれています。

出力フォーマット

        最小ステップ数を出力するか、解決策が存在しない場合は -1 を出力します。

入力サンプルと出力サンプル

入力

12345678.123.46758 
_

出力

3

参照コード

#include<iostream>
#include<queue>
#include<map>
using namespace std;
int dx[4]={1,-1,3,-3};
map<string,int> mp;
string s,e;
struct node
{
    string str;
    int step;
};
bool no(int x,int y)
{
    if(x==2&&y==3) return 1;
    if(x==3&&y==2) return 1;
    if(x==5&&y==6) return 1;
    if(x==6&&y==5) return 1;
    return 0;
}
void bfs()
{
    queue<node> q;
    node tmp,now;
    tmp.step=0;
    tmp.str=s;
    q.push(tmp);
    while(q.size())
    {
        now=q.front();q.pop();
        if(now.str==e)
        {
            cout<<now.step<<endl;
            return;
        }
        int x=now.str.find('.');
        for(int i=0;i<4;i++)
        {
            s=now.str;
            int y=x+dx[i];
            if(y<0||y>8) continue;
            if(no(x,y)) continue;
            swap(s[x],s[y]);
            if(mp[s]) continue;
            mp[s]=1;
            tmp.step=now.step+1;
            tmp.str=s;
            q.push(tmp);
        }
    }
    cout<<"-1"<<endl;
}
int main()
{
    cin>>s>>e;
    mp[s]=1;
    bfs();
    return 0;
}

ある例から別の例への推論 - ラッキーナンバー

トピックの背景

        ラッキーナンバーはポーランドの数学者ウラムにちなんで名付けられました。素数の生成と同様の「ふるい法」を用いて生成されます。

まず自然数1,2,3,4,5,6,....        を 1 から書きます。

        1は最初の幸運な数字です。

        番号 2 から始めます。シリアル番号が 2 で割り切れる項目をすべて削除し、1 _ 3 _ 5 _ 7 _ 9 …に変更します。

        それらを絞り込んで、1 3 5 7 9 ...のように並べ替えます。

        このとき、2番目のラッキーナンバーは「3」なので、連番の3で割り切れる数字をすべて削除します。シリアル番号自体が 3 で割り切れるかどうかではなく、シリアル番号の位置であることに注意してください!! 削除されたものは5、11、17、...である必要があります。

        このとき、7が3番目のラッキーナンバーなので、7で割り切れる連番位置(19,39,...)を削除します。

        最後に残ったシーケンスは次のようなものです: 1、3、7、9、13、15、21、25、31、33、37、43、49、51、63、67、69、73、75、79、... 。

入力フォーマット

        2 つの正の整数 mn をスペースで区切って入力します (m < n < 1000*1000)

出力フォーマット

        プログラムは、m から n までのラッキーナンバーの数を出力します (m と n を除く)。

入力サンプルと出力サンプル

入力サンプル

1 20

出力サンプル

5

参照コード

# include<stdio.h>
# define MAX 50000

int create_luck(int * );
int num_luck(int *,int,int,int);

int main(void)
{
  int luck[MAX] = {0};
  int max,n,i;
  int num1,num2;/*标定范围*/

  max = create_luck(luck);/*幸运数生成*/
  scanf("%d%d",&num1,&num2);
  n = num_luck(luck,max,num1,num2);/*计算num1到num2之间的幸运数个数*/
  printf("%d\n",n);
  /*for(i=0;i<max;i++){
    printf("%d\t",luck[i]);//遍历幸运数
  }*/
  return 0;
}

int create_luck(int * luck)
{
  /*1~2*MAX的幸运数*/
  int i,j;
  int point_pre=1;/*point_pre用来标记被除数数组下标,也就是上一次循环找到的幸运数*/
  int point_max=MAX;/*point_max用来标记遍历一遍完成删除之后剩余的元素个数*/

  /*原始奇数数组,第一次将偶数完全删除,所以所有幸运数在奇数中生成即可*/
  for(i=0;i<MAX;i++){
    luck[i] = 2*i+1;
  }
  /*生成幸运数*/
  while(point_pre < point_max){
    for(j = point_pre, i = point_pre; j<point_max; j++){/*i,j从point_pre开始,因为point_pre之前的数都已经是幸运数了*/
      if((j+1) % luck[point_pre] != 0){
        luck[i] = luck[j];
        i++;
      }
    }
    point_pre++;/*幸运数个数加1,也是内层循环初始值后移1*/
    point_max = i;/*便遍历一遍之后,i之前的符合局部条件(取余不为0),point_max则划分界限*/
  }
  /*注意:循环完成时,point_pre之前的数都是幸运数,
  但是数组定义长为MAX,point_max之后的数(MAX-point_pre个)是无用的
  */

  return point_max;
}
int num_luck(int * luck,int max,int num1,int num2)
{
  int i,n=0;

  for(i=0;i < max;i++){/*i<point_max是为了确保不会找到无用的数组后半部分*/
    if(luck[i] >= num2)
      break;
    else if(luck[i] > num1)/*不包含num1和num2*/
      n++;
  }

  return n;
}

おすすめ

転載: blog.csdn.net/leyang0910/article/details/131028726