回 帖 发 新 帖 刷新版面

主题:递归与回溯的常见题目(选自GCC入门题集)

//////////////////////////////////////////////////////////////////////////////
//
//  4. 在N行N列的数阵中, 数K(1〈=K〈=N)在每行和每列中出现且仅
//  出现一次,这样的数阵叫N阶拉丁方阵。例如下图就是一个五阶拉丁方阵。
//  编一程序,从键盘输入N值后,打印出所有不同的N阶拉丁方阵,并统计个数。
//
//        1  2  3  4  5
//        2  3  4  5  1
//        3  4  5  1  2
//        4  5  1  2  3
//        5  1  2  3  4
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"
#define  N  4

static int a[N][N], count;

bool legal(int row, int col)
{
    int i;
    for(i = 0; i < row; i++)
    {
        if(a[i][col] == a[row][col])
            return false;
    }
    for(i = 0; i < col; i++)
    {
        if(a[row][i] == a[row][col])
            return false;
    }
    return true;
}

void trial(int row, int col, FILE *fp)
{
    int i, j;
    if(row == N)
    {        
        printf("*********** %d **********\n", ++count);
        fprintf(fp, "*********** %d **********\n", count);
        for(i = 0; i < N; i++)
        {
            for(j = 0; j < N; j++)
            {
                printf("%5d", a[i][j]);
                fprintf(fp, "%5d", a[i][j]);
            }
            putchar(10);
            fputc(10, fp);
        }
    }
    for(i = 1; i <= N; ++i)
    {
        a[row][col] = i;
        if(legal(row, col))
            trial((row*N+col+1)/N, (row*N+col+1)%N, fp);
    }
}

void main()
{
    FILE *fp = fopen("latin.txt", "w");
    trial(0, 0, fp);
}

//////////////////////////////////////////////////////////////////////////////
//
// 11. 巧排数字。将1、2、...、20这20个数排成一排,使得相邻的两个数之
//     和为一个素数,且首尾两数字之和也为一个素数。编程打印出所有的排法。
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"
#include "math.h"

static used[21], link[21];
bool isprime(int a)
{
    for(int i = 2; i <= sqrt(a); i++)
    {
        if(!(a%i))
            return false;
    }
    return true;
}

void trace(int node)
{
    int i;
    if((node == 21) && isprime(link[20] + link[1]))
    {
        for(i = 1; i < 21; i++)
            printf("%4d", link[i]);
        putchar(10);
    }
    for(i = 1; i <= 20; i++)
    {
        if(!used[i])
        {
            link[node] = i;
            used[i] = 1;
            if(isprime(link[node]+link[node-1]))
                trace(node+1);
            used[i] = 0;
        }
    }
}

void main()
{
    trace(1);
}

回复列表 (共5个回复)

沙发

//////////////////////////////////////////////////////////////////////////////
//
// 15. 已知6个城市,用c[i,j]表示从i城市到城市j是否有单向的直达汽车
//
// (1=<i〈=6,1〈=j〈=6), c[i,j]=1 表示城市i到城市j有单向直达汽
// 车; 否则 c[i,j]=0.  试编制程序,对于给出的城市代号i,打印出从该城市出
// 发乘车(包括转车)可以到达的所有城市。 
//////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#define  N  6

int visited[N] = {0};

void visit(int c[][N], int i)
{
    if(!visited[i])
    {
        visited[i] = 1;
        for(int j = 0; j < N; j++)
            if(c[i][j] && !visited[j])
                visit(c, j);
    }
}

void main( void )
{
    int  c[N][N], i, j, n;
    
    srand((unsigned)time(NULL));
    for (i = 0; i < N; i++ )
    {
        for(j = 0; j < N; j++)
        {
            c[i][j] = rand()%2;
            printf( "%6d", c[i][j]);
        }
        putchar('\n');
    }

    scanf("%d", &n);
    assert(n < N);
    visit(c, n);
    for (i = 0; i < N; i++ )
    {
        if(visited[i])
            printf( "%6d", i);
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// 20. (N皇后) 在国际象棋的棋盘上放置N个皇后,使其不能互相攻击,即任意
// 两个皇后不能处在棋盘的同一行,同一列,同一斜线上,试问共有多少种摆法? 
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"
#include "conio.h"
#define N 8

static int a[N][N], count;
bool legal(int row, int col)
{
    int i, j;
    for(i = 0; i < row; i++)
        if(a[i][col])
            return false;
    for(j = 0; j < col; j++)
        if(a[row][j])
            return false;
    for(i = row-1, j = col-1; (i>=0) &&(j>=0); i--, j--)
        if(a[i][j])
            return false;
    for(i = row-1, j = col+1; (i>=0) &&(j<N); i--, j++)
        if(a[i][j])
            return false;
    return true;
}

void trial(int row)
{
    int p, col;
    if(row == N)
    {
        ++count;
        printf("********%d*********\n", count);
        for(p = 0; p < N; p++)
        {
            for(col = 0; col < N; col++)
                printf("%4d", a[p][col]);
            printf("\n");
        }
    }
    else
    {
        for(col = 0; col < N; col++)
        {
            a[row][col] = 1;
            if(legal(row, col))
                trial(row+1);
            a[row][col] = 0;
        }
    }
}

void main()
{    
    trial(0);
}

板凳

//////////////////////////////////////////////////////////////////////////////
//
//21. 请设计一个程序,由计算机把1.. ̄.8的八个自然数填入图中,使得横、
// 竖、对角任何两个相邻的小方格中的两个数是不连续的。(下图右侧的 4 个图
// 为禁止的情形).
//
//            ┌─┐          ┌─┐               ┌─┐
//            │  │          │4│               │8│
//        ┌─┼─┼─┐      └─┼─┐       ┌─┼─┘
//        │  │  │  │          │5│       │7│
//        ├─┼─┼─┤          └─┘       └─┘
//        │  │  │  │      ┌─┐
//        └─┼─┼─┘      │6│           ┌─┬─┐
//            │  │          ├─┤           │1│2│
//            └─┘          │7│           └─┴─┘
//                            └─┘
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"
#include "string.h"
#include "math.h"

int a[4][3];
int count = 0;

bool legalelem(int row, int col)
{
    switch (row)
    {
    case 0:
    case 3:
        if(col == 1)
            return true;
        else
            return false;
    case 1:
    default:
        return true;
    }
}

bool islegal(int row, int col)
{
    int i, j;
    for(i = row-1; i <= row+1; i++)
    {
        if(i < 0 || i > 3)
            continue;
        for(j = col-1; j <= col+1; j++)
        {
            if(j < 0 || j > 2)
                continue;
            if(abs(a[i][j] - a[row][col]) == 1)
                return false;
        }
    }
    return true;
}

void trace(int n)
{
    int i, j;
    if(n > 8)
    {
        ++count;
        printf("\n********** %d **********\n", count);
        for(i = 0; i < 4; i++)
        {
            for(j = 0; j < 3; j++)
            {
                if(legalelem(i, j))
                    printf("%6d", a[i][j]);
                else
                    printf("%*s", 6, "");
            }
            putchar(10);
        }
        return;
    }
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 3; j++)
        {
            if(a[i][j] == -1 && legalelem(i, j))
            {
                a[i][j] = n;
                if(islegal(i, j))
                    trace(n+1);
                a[i][j] = -1;
            }                
        }
    }        
}

void main()
{
    int i, j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 3; j++)
            a[i][j] = -1;
    trace(1);
}

3 楼

//////////////////////////////////////////////////////////////////////////////
//
// 22. 在一个4*4的小方格(如图所示)中放置8个*号,使得每行每列放且
// 仅放两个*号。
//
//          ┌─┬─┬─┬─┐
//          │*│*│  │  │
//          ├─┼─┼─┼─┤
//          │*│  │*│  │
//          ├─┼─┼─┼─┤
//          │  │*│  │*│
//          ├─┼─┼─┼─┤
//          │  │  │*│*│
//          └─┴─┴─┴─┘
//
// 求出所有的基本解。
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"
#define N 4

static int a[N][N], count;

bool legal(int row, int col)
{
    int sum, p;
    for(sum = 0, p = 0; p < row; p++)
        sum += a[p][col];
    if(sum < 2)
    {
        for(sum = 0, p = 0; p < col; p++)
            sum += a[row][p];
        if(sum < 2)
            return true;
        else
            return false;
    }
    else
        return false;
}

void trial(int row)
{
    if(row == N)
    {
        ++count;
        printf("******** %d ********\n", count);
        for(int p = 0; p < N; p++)
        {
            for(int q = 0; q < N; q++)
                printf("%4d", a[p][q]);
            printf("\n");
        }
    }
    else
    {
        for(int j1 = 0; j1 < N-1; j1++)
        {
            a[row][j1] = 1;
            if(legal(row, j1))
            {
                for(int j2 = j1+1; j2 < N; j2++)
                {
                    if(!a[row][j2])
                    {
                        a[row][j2] = 1;
                        if(legal(row, j2))
                            trial(row+1);
                        a[row][j2] = 0;
                    }
                }
            }
            a[row][j1] = 0;
        }
    }
}

void main()
{
    trial(0);
}

4 楼

//////////////////////////////////////////////////////////////////////////////
//
// 38. 有一集合中有 N 个元素,每个元素均为自然数。给定一个 total (假设每个
// 元素值均小于total),求满足条件的所有子集,子集中各元素之和应等于total。
//////////////////////////////////////////////////////////////////////////////
#include "stdio.h"

int a[] = {1, 2, 3, 4, 7, 10};
const int N = sizeof(a)/sizeof(int);

void trial(int i,int j, int a[], int b[], int total)
{
    if(i == N) //不能和下面的if(b[0] == total)合写成if(i == N && b[0] == total),因为这个if为递推的回归条件语句,要单独做判断,如果和写的话,则只有当i ==N且
b[0] == total 时条件才为真时递推过程才结束
    {
        if(b[0] == total)
        {
            for(int p = 1; p < j; p++)
                printf("%5d", b[p]);
            printf("\n");
        }
    }
    else
    {
        b[0] += a[i];
        b[j] = a[i];
        trial(i+1, j+1, a, b, total);
        b[0] -= a[i];
        b[j] = 0;
        trial(i+1, j, a, b, total);
    }
}

void main()
{
    int *b = new int[N], i, total;
    printf("a[%d] = {", N);
    for(i = 0; i < N; i++)
        printf(" %d,", a[i]);
    printf("}\ninput the total, insure its value larger than each element of array a:");
    scanf("%d", &total);
    b[0] = 0;
    trial(0, 1, a, b, total);
}

5 楼

大家继续添加

我来回复

您尚未登录,请登录后再回复。点此登录或注册