100例(20)のC言語プログラミング:Guohe銅

実施例20のCu Guohe

タイトル説明

1、A点で市松Guohe銅、来る目標点Bの必要性が存在します。死の歩行ルール:ダウンして、または右にすることができます。ボード上の任意の点は、馬(図1中の点C)の反対側、馬がジャンプし、他の馬の制御点と呼ばれる全てのポイントアップステップ点があるが。例えば、図中の馬に。1つのC点は9点(図P1、P2、...、P8及びC)を制御することができます。死はポイントに他の馬を制御することはできません。

キーボード入力によって表現、点(0,0)、B点(N、M)(N、Mはキーボード入力によって、50を超えない整数である。)、同馬の位置座標を座標、及びCを合意したチェス盤< > A、Cながら<> B.

プログラミング、パスの数は点Bに、点Aからストロークに達することができる計算

   Guohe Cu及び制御ボード図1馬の反対側に

入力形式

四つのデータライン、それぞれ座標点Bと馬の座標を表します。

出力フォーマット

すべてのパスの数を示すデータです。

サンプル入力

6 6 3 3

サンプル出力

6

        (1)プログラミングのアイデア。

        ボード上の任意の点に到達するためのボードGuoheのCu(0,0)のポイントは、唯一の両方向における左と上縁から来ることができます。したがって、パスの数の一点に達し、それはパスと数の2点の隣接する左側に等しくされます。

        F [I] [J] = F [I-1]〜[J] + F [I] [J-1]。

        この方法は、(制御点馬障害と呼ばれる)障害物がある場合でも、再帰法は限り、また、完全に適用可能であり、我々は最後まで開始頂点から再帰的なパスの数を求める列(又は行)によって使用されてもよいですパス番号パス番号はこの時点であるF [i] [j]が到達点(i、j)を示し、0に設定することができる達し、G [i] [j]は点(i、j)はバリアを表します次のように再帰的な式は次のとおりです。

        F [0] [0] = 1初期点直接到達可能。

        F [i]が[0] = F [I-1] [0](I> 0、G [i]が[0] = 0)//左边界

        F [0] [J] = F [0] [J-1](J> 0、G [0] [j] = 0)//境界

        F [I] [J] = F [I-1]〜[J] + F [I] [J-1](I> 0、J> 0、G [x、y] = 0)//递推式

        (2)ソース。

書式#include <stdio.hに>

メインint型()

{

    INT I、J、X、Y、N、M、禁止[51] [51]。 

    long intの年[51] [51]。 

    INTのDX [8] = { - 2、-1,1,2,2,1、-1、-2}。

    int型DY [8] = {1,2,2,1、-1、-2、-2、-1}。

    scanf関数( "%D%D%D%D"、&N、&M、およびX&Y)。 

    (; I <= N; I ++ I = 0)するため

        用(J = 0であり、j <= Mであり、j ++)

        {

            禁断の[I] [J] = 0;

            年[I] [J] = 0;

        }

    年[0] [0] = 1; 

    禁止[X] [Y] = 1。

    以下のための式(I = 0、I <8; I ++)

            IF(X + DX [I]> = 0 && X + DX [I] <= N && Y + DYの[I]> = 0 && Y + DY [I] <= M)

                   禁止[X + DX [I]、[Y + DY [I] = 1。

   (; I <= N; I ++ I = 1の)のための 

        (禁断の[I] [0] == 0)場合 

            年[I] [0] = 1; 

        他に休憩; 

  以下のための式(I = 1; I <= M; I ++) 

        (禁断の[0] [I] == 0)の場合 

            年[0] [I] = 1。 

        他に休憩; 

   (; I <= N; I ++ I = 1の)のための 

        用(J = 1; J <= Mであり、j ++) 

            もし(禁断の[I] [J] == 0) 

                年[I] [J] =年間[I-1]〜[J] +年[I]、[J-1]。 

    printf( "%のLD \ n" は、ANS [n]は[M])。

    0を返します。 

}

練習20

馬の走行経路20-1

問題の説明

N * Mボードを備えた(2 <= N <= 50,2 <= M <= 50)、任意の時点で基板チャイニーズチェス馬、図がある。2()は、図1に示します。(2)図(B)に示すように、馬、すなわち4種の動きを右に行くことができる(1)ワードに馬の歩行:馬は、ルールを歩いています。

プログラムを作成し、入力N M、馬が右上隅(N、M)の左ボード底(1,1)からのパスを見つけるの。例えば、N = 4、M = 4、出力路(1,1)を入力 - >(2,3) - >(4,4)。図中のパス。2(C)に示します。パス、出力がある場合は、「いいえ!」

   

 2馬歩行図チェス盤

入力形式

終点の位置座標を示す2つのラインデータ。

出力フォーマット

走行可能パス。可能な移動経路が複数いる場合、いずれかを出力することができます。パスがある場合は、出力が「いいえ!」。

サンプル入力

10 10

サンプル出力

(1,1) - >(2,3) - >(3,5) - >(4,7) - >(5,9) - >(6,7) - >(7,9) - >( 9,8) - >(10,10)

        (1)プログラミングのアイデア

        最初のiが横所定の基板であり、縦軸はJ、M用のN×ボード、1からnまでのiの値として定義され、jは1からMまでの値です。ボード上の任意の点は、座標(i、j)と表すことができます。

        馬を移動させるための方法であって、変数kは方向(1,2,3,4)を移動させる4種類によって表され;及び前記オフセット値を移動させる方法と、各オフセット値は、配列に格納されているDX及びDY 、表1に示します。

オフセット値を移動させる方法の4種類の表1に対応

K

DX [K]

これらの[K]

1

2

1

2

2

-1

3

1

2

4

1

-2

        馬の歩行の規則に従って、馬は、(i-DX [k]は、J-DY [K])(I、J)で歩くことができます。ロング(1,1)から馬としては、(i-DX [k]は、J-DY [k]が)、私たちはもちろん、(i、j)を来ることができるようになりますことを行ったとして、我々は馬がボード上の座標を取っていることを確認する必要があります。

        、IN(n、m)は左再帰を出発点として、(I-DX [k]は、J-DY [K])は(1から1を見つける位置(1,1)である場合、再帰1)パスの(n、m)とします。

        プログラムで使用可能な二次元アレイは、(n、m)は初期値[n]は、[M]は(-1、-1)を設定し、再帰左(終了を示す)エンドポイントから後方に用いたチェッカーボード法で表されますステップ(n、m)は(i、j)はから行くことができる場合、IN(N、M)[I] [J]に格納されているであろう。表2に示すように、[3] [2]及び[2] [3]の値が(4,4)であり、2つの点が座標(4,4)から到達可能表します。(1,1)から(2,3)、(3,2)は、2つの点に到達するので、[1] [1]は、缶の任意の2点に記憶されています。再帰の終了後、[1]〜[1]の値は、パスが存在しない、または[1] [1]は出力経路に沿って押すために馬の歩行次に、座標の値であると(0,0)である場合。

表2 = 4 N、M = 4、ケースアレイの割り当て

 

 

 

[4] [4] = { - 1、-1}

 

[2] [3] = {4,4}

 

 

 

 

[3] [2] = {4,4}

 

[1] [1] = {2,3}

 

 

 

        (2)ソース。

書式#include <stdio.hに>

メインint型()

{

    INTのDX [5] = {0,2,2,1,1}、すなわち[5] = {0.1、-1.2、-2}。

    構造体のポイント

     {

            int型のx;

            int型のy;

     }。

    構造体A点[51] [51]。

    INT I、J、N、M、K。

    以下のための式(I = 0、I <51; I ++)

            用(J = 0であり、j <51; J ++)

                      = 0 [I] [J] .X = A [i]は[J] .Y。

    scanf関数( "%D%D"、&N、&M)。

    [n]は[M] .X = -1; //末端標識

    [n]は[M] .Y = -1。

    (iはN =、I> = 2; i--)用//倒推

      用(J = 1; J <= Mであり、j ++)

       ([I] [J] .X!= 0)の場合

        (; K <= 4、K ++、K = 1)のために

        {

                 [I-DX [K] [J-DY [K] X = I。

                [I-DX [K] [J-DY [K] Y = J。

        }

         IF([1] [1] .X == 0)

                   printf( "いいえ\ n個!");

        他に//パスがあります

       {

              I = 1; J = 1;

             printf( "(%dを、%のD)"、I、J)。

             しばらく([I] [J] .X = - !1)

            {

                K = I。

                iは、[I] [j]を= .X。J = [K] [J] .Y。

                printf( " - >(%d個、%d)は"、i、j)は、

            }

            printf( "\ n" は);

         }

         0を返します。

}

正方形の数(A)を取る20-2

タイトル説明

他のボックス番号0に配置されている間グリッドは、我々は、いくつかの正の整数を満たす前記図(N≤9)とN×Nの正方形。(例を参照)、次のとおりです。

某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点走到B点,试找出1条这样的路径,使得取得的数之和为最大。

输入格式

输入的第一行为一个整数N(表示N×N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出格式

只需输出一个整数,表示找出的1条路径上取得的最大的和。

输入样例

8

2 3 13

2 6 6

3 5 7

4 4 14

5 2 21

5 6 4

6 3 15

7 2 14

0 0 0

输出样例

36

        (1)编程思路。

        因为行走的方向是:可以向下行走,也可以向右走。因此,位置(i,j)可以由上边的格子(i-1,j)走到,也可以由左边的格子(i,j-1)走到。

        设f[i][j]表示走到格子(i,j)处所取方格数的最大值,a[x][y]表示格子(x,y)上的数字。显然有

        f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];

        初始时   f[1][1]=a[1][1]。

       (2)源程序。

#include <stdio.h>

int max(int a,int b)

{return a<b?b:a;}

int main()

{

    int f[10][10]={0}, a[10][10]={0};

    int n;

    scanf("%d",&n);

   while(1)

    {

                   int x, y, w;

                   scanf("%d%d%d",&x,&y,&w);

                   if (x==0 && y==0 && w==0) break;

                   a[x][y]=w;

    }

    f[1][1]=a[1][1];

    int i, j;

    for (i=1;i<=n;i++)

     {

                 for (j=1;j<=n;j++)

                 {

                        f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];

                   }

     }

     printf("%d\n",f[n][n]);

    return 0;

}

20-3  方格取数(二)

题目描述

设有N×N的方格图(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下所示(见样例):

某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

输入格式

输入的第一行为一个整数N(表示N×N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出格式

只需输出一个整数,表示2条路径上取得的最大的和。

输入样例

8

2 3 13

2 6 6

3 5 7

4 4 14

5 2 21

5 6 4

6 3 15

7 2 14

0 0 0

输出样例

67

        (1)编程思路1。

        本题要求找到2条从(1,1)到(n,n)的路径,被取走的格子里的数变为0,使得在两条路径上格子中数之和最大时,就成为了“二取方格数”问题。

        最容易想到的就是先后做两次单条路径“方格取数”,这一算法的本质是贪心,但这是错误的,反例如下:

3

4 

5

0 

0 

0

2 

8 

2

        贪心:第一路径:3->4->8->2  (17)    第二路径:5 (5)   总和为22 

        事实上我们可以将所有的数都取完,总和为24。 

        解决“二取方格数”问题需要用到“多进程DP”。即解决本题时,由于此人从A点到B点共走两次,要找出2条这样的路径,因此可以考虑为两个人同时从A走到B。

设f[i][j][k][l]为第一个人走到(i,j),第二个人走到(k,l)时方格取数能达到的最大值,a[x][y]表示格子(x,y)上的数字。

状态转移情况如下:

1)两个人同时向右走

f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k-1][l]+a[i][j]+a[k][l]);

2)两个人同时向下走

f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l-1]+a[i][j]+a[k][l]);

3)两个人分别向右和向下走

f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l-1]+a[i][j]+a[k][l]);

4)两个人分别向下和向右走

f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k-1][l]+a[i][j]+a[k][l]);

当然,若两人走到了同一个格子,即(i,j)和(k,l)是同一个点,f[i][j][k][l]值还要减去a[i][j]。

       两个人都走到(n,n)格子时,得到答案,即f[n][n][n][n]为所求。

     (2)源程序1。

#include <stdio.h>

int max(int a,int b)

{return a<b?b:a;}

int main()

{

    int f[10][10][10][10]={0}, a[10][10]={0};

    int n;

    scanf("%d",&n);

    while(1)

    {

                   int x, y, w;

                   scanf("%d%d%d",&x,&y,&w);

                   if (x==0 && y==0 && w==0) break;

                   a[x][y]=w;

    }

    f[1][1][1][1]=a[1][1];

    int i, j, k, l;

    for (i=1;i<=n;i++)

     {

                   for (j=1;j<=n;j++)

                          for (k=1;k<=n;k++)

                                     for (l=1;l<=n;l++)

                                     {

                                               f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k-1][l]+a[i][j]+a[k][l]);

                                               f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l-1]+a[i][j]+a[k][l]);

                                               f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l-1]+a[i][j]+a[k][l]);

                                               f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k-1][l]+a[i][j]+a[k][l]);

                                               if(i==k && j==l)f[i][j][k][l]-=a[i][j];

                                     }

     }

     printf("%d\n",f[n][n][n][n]);

    return 0;

}

        (3)编程思路2。

        按思路1的方法,由于状态总共有n^4种,所以时间复杂度为O(n^4)。

        如果让两个人同时从(1,1)处出发,并同时向前延伸,那么当两个人都走了k步,两条路径都已经各自包含k个方格时,两条路径的末端必同在整个矩阵的第k条对角线上。如下图3所示。

图3  行走对角线示意图

        由图3可知,走1步可到达(1,1)格子(标注为2),走两步可到达(1,2)或(2,1)格子(标注为2),走三步可到达(1,3)、(2,2)或(3,1)格子(标注为4),……。

         由图可知,对于每一条路径,向右延伸的格子数+向下延伸的格子数=k(定值),也就是末端两个格子的纵横坐标之和=k。

        所以我们只需要知道两路径末端所在的行编号x1,x2以及两末端所在对角线编号k,就可以确定末端节点的位置(x1,k-x1),(x2,k-x2)。这样,可以只枚举对角线、x1和x2。

        设状态f[l][x1][x2]第一个人横坐标为x1(即第一个路径末端在第x1行),第二个人横坐标为x2(即第二路径末端在第x2行),且两末端同在第k条对角线上时的最优解。

        到达状态f[l][x1][x2]有有4种可能:

1)第1人从x1的左边向右到达x1,第2人从x2的左边向右到达x2,其前一状态应为f[k-1][x1-1][x2-1];

2)第1人从x1的上边向下到达x1,第2人从x2的上边向下到达x2,其前一状态应为f[k-1][x1][x2];

3)第1人从x1的左边向右到达x1,第2人从x2的上边向下到达x2,其前一状态应为f[k-1][x1-1][x2];

4)第1人从x1的上边向下到达x1,第2人从x2的左边向右到达x2,其前一状态应为f[k-1][x1][x2-1];

这样,可以得到状态转移方程:

tmp=max(max(f[k-1][x1-1][x2-1],f[k-1][x1][x2]),max(f[k-1][x1-1][x2],f[k-1][x1][x2-1]));

f[k][x1][x2]=max(f[k][x1][x2],tmp+a[x1][k-x1]+a[x2][k-x2]);

同样,如果点(x1,k-x1)和(x2,k-x2)重合了,需要减去一个点中的数(每个点只能取一次)。

       (4)源程序2。

#include <stdio.h>

int max(int a,int b)

{return a<b?b:a;}

int main()

{

    int f[19][10][10]={0}, a[10][10]={0};

    int n;

    scanf("%d",&n);

    while(1)

    {

                   int x, y, w;

                   scanf("%d%d%d",&x,&y,&w);

                  if (x==0 && y==0 && w==0) break;

                  a[x][y]=w;

     }

    int d=n*2;

    f[2][1][1]=a[1][1];

    for (int i=3;i<=d;i++)

    {

                   int c=i<n+1?i:n+1;

                   int s=i>n?i-n:1;

                   for(int j=s;j<c;j++)

                            for(int k=s;k<c;k++)

                            {

                                     int x1=j,x2=k,y1=i-j,y2=i-k;

                                     int tmp=max(max(f[i-1][x1-1][x2-1],f[i-1][x1][x2]),

                                     max(f[i-1][x1-1][x2],f[i-1][x1][x2-1]));

                                     f[i][x1][x2]=max(f[i][x1][x2],tmp+a[x1][y1]+a[x2][y2]);

                                     if (x1==x2&&y1==y2)  f[i][x1][x2]=f[i][x1][x2]-a[x1][y1];

                            }

    }

   printf("%d\n",f[d][n][n]);

    return 0;

おすすめ

転載: www.cnblogs.com/cs-whut/p/11971237.html