C language programming of 100 cases (20): Guohe Cu

Example 20 Guohe Cu

Title Description

1, at point A there is a checkerboard Guohe Cu, the target point B need to come. Death walking rules: can be down, or right. At the same time either on the board there is a little of the other horses (point C in Figure 1), the point where the horse jumps and step up all the points called control points other horses. For example, on a horse in FIG. 1 C point can control the nine points (figure P1, P2, ..., P8 and C). Death can not control points other horses.

Chessboard coordinate representation, A point (0,0), B point (n, m) (n, m is an integer not exceeding 50, by keyboard input), the position coordinates of the same horse by keyboard input, and agreed C < > A, while C <> B.

Programming, calculates the number of paths can reach the stroke from point A to point B.

   Guohe Cu and on the other side of the control board Figure 1 horse

Input Format

Four data line, respectively represent the coordinates of the coordinate point B and horses.

Output Format

A data representing the number of all paths.

SAMPLE INPUT

6 6 3 3

Sample Output

6

        (1) programming ideas.

        A point in the board Guohe Cu (0,0) to reach any point on the board, can only come from the left and top edges in both directions. Therefore, to reach the number one point of the path, and it is equal to the adjacent left two points on the path and number:

        F[i][j] = F[i-1][j] + F[i][j-1]。

        The method may be used by a column (or row) we obtain the number of recursive path from the start vertex to the end, even if there are obstacles (called the control points horse disorder), the recursion method is also fully applicable, as long as the path number path number reaches this point can be set to 0, a F [i] [j] denotes reach point (i, j) is, g [i] [j] represents the point (i, j) Accessible recursive equation is as follows:

        F [0] [0] = 1 the initial point directly reachable.

        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) // the boundary

        F[i][j] = F[i-1][j] + F[i][j-1]   (i > 0,j > 0,g[x, y] = 0) // 递推式

        (2) source.

#include <stdio.h>

int main ()

{

    int i,j,x,y,n,m,forbidden[51][51]; 

    long int year [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); 

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

        for (j=0;j<=m;j++)

        {

            forbidden[i][j]=0;

            years [i] [j] = 0;

        }

    years [0] [0] = 1; 

    forbidden[x][y]=1;

    for (i=0;i<8; i++)

            if (x+dx[i]>=0 && x+dx[i]<=n && y+dy[i]>=0 && y+dy[i]<=m)

                   forbidden[x+dx[i]][y+dy[i]]=1;

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

        if (forbidden[i][0]==0) 

            years [i] [0] = 1; 

        else break; 

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

        if (forbidden[0][i]==0) 

            years [0] [i] = 1; 

        else break; 

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

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

            if (forbidden[i][j]==0) 

                years [i] [j] = years [i-1] [j] + years [i] [j-1]; 

    printf("%ld\n",ans[n][m]);

    return 0; 

}

Exercise 20

Horse traveling path 20-1

Problem Description

N * m provided with a board (2 <= n <= 50,2 <= m <= 50), at any point there is a board Chinese chess horse, FIG. 2 (a) shown in FIG. Horse is walking rules: (1) the horse walking on the word; (2) the horse can go right, i.e. four species moves as shown in (b) in FIG.

Write a program, and input n m, horses find a path from the board bottom left (1,1) to the upper right corner (n, m) of. For example: Enter n = 4, m = 4, the output path (1,1) -> (2,3) -> (4,4). The path in FIG. 2 (c) shown in FIG. If there is a path, the output "No!"

   

 2 and horse walking FIG chessboard

Input Format

Two line data indicating position coordinates of the end point.

Output Format

A possible travel path. If a plurality of possible travel path, any one can be output. If there is a path, the output "No!".

SAMPLE INPUT

10 10

Sample Output

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

        (1) programming ideas

        First i is the abscissa predetermined board, the vertical axis is defined as j, a board for n × m, the value of i from 1 to n, j is a value from 1 to m. Arbitrary point on the board can be represented by the coordinates (i, j).

        A method for moving the horse, the variable k is represented by four kinds of moving direction (1,2,3,4); and each offset value with a method of moving said and offset values ​​are stored in arrays dx and dy , as shown in table 1.

Table 1 correspond to four kinds of method of moving the offset value

K

Dx[k]

These [k]

1

2

1

2

2

-1

3

1

2

4

1

-2

        According to the rules of the horse walking, horses can walk by the (i-dx [k], j-dy [k]) (i, j). As long as the horse from (1,1) went to (i-dx [k], j-dy [k]), we will be able to come (i, j), of course, we must ensure that the horse is taking the coordinates on the board.

        In (n, m) as a starting point to the left recursive, recursive when the (i-dx [k], j-dy [k]) is a position (1,1), to find the one from (1, 1) to (n, m) of the path.

        A two-dimensional array available in the program represented by a checkerboard method using backwards from the end point (n, m) left recursive, set the initial value a [n] [m] is (-1, -1) (indicates the end) If step can go (n, m) from the (i, j), will be (n, m) is stored in a [i] [j] in. As shown in Table 2, a [3] [2] and a [2] [3] values ​​are (4,4), represents the two points can be reached from the coordinates (4,4). From (1,1) to reach the (2,3), (3,2) two points, so a [1] [1] is stored in any two points of a can. After the end of recursion, if a [1] [1] value is (0,0) with the path does not exist, or a [1] [1] is the value of the coordinates of the horse walking Next, in order to push along the output path.

Table 2 N = 4, when M = 4, the assignment of a case where the array

 

 

 

A[4][4]={-1,-1}

 

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

 

 

 

 

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

 

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

 

 

 

        (2) source.

#include <stdio.h>

int main ()

{

    int dx [5] = {0,2,2,1,1}, that [5] = {0.1, -1.2, -2};

    struct point

     {

            int x;

            int y;

     };

    struct point a[51][51];

    int i,j,n,m,k;

    for(i=0;i<51;i++)

            for (j=0;j<51;j++)

                      a[i][j].x=a[i][j].y=0;

    scanf("%d%d",&n,&m);

    a [n] [m] .x = -1; // end labeled

    a[n][m].y=-1;

    for (i=n;i>=2;i--)       // 倒推

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

       if (a[i][j].x!=0)

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

        {

                 a[i-dx[k]][j-dy[k]].x=i;

                a[i-dx[k]][j-dy[k]].y=j;

        }

         if (a[1][1].x==0)

                   printf("No!\n");

        else // there is a path

       {

              i=1;  j=1;

             printf("(%d,%d)",i,j);

             while (a[i][j].x!=-1)

            {

                k=i;

                i=a[i][j].x;  j=a[k][j].y;

                printf("->(%d,%d)",i,j);

            }

            printf("\n");

         }

         return 0;

}

20-2 taking the number of squares (a)

Title Description

N × N squares with FIG (N≤9), wherein the grid we fill some positive integer, while the other is placed in the box numbers 0. As follows (see examples):

某人从图的左上角的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;

Guess you like

Origin www.cnblogs.com/cs-whut/p/11971237.html