Betsy's Tour

题意:摘自NOCOW翻译(http://www.nocow.cn/index.php/Translate:USACO/betsy

翻译

一个正方形的镇区分为 N*N 个小方块(1 <= N <= 7)。农场位于方格的左上角,集市位于左下角。贝茜穿过小镇,从左上角走到左下角,刚好经过每个方格一次。当 N=3 时,贝茜的漫游路径可能如下图所示:

----------------
|    |    |    |
| F**********  |
|    |    | *  |
------------*---
|    |    | *  |
|  *****  | *  |
|  * | *  | *  |
---*---*----*---
|  * | *  | *  |
|  M | ******  |
|    |    |    |
----------------

写一个程序,对于给出的 N 值,计算贝茜从农场走到集市有多少种唯一的路径。

[编辑]格式

PROGRAM NAME: betsy

INPUT FORMAT

行 1: 一个整数 N (1 <= N <= 7)

OUTPUT FORMAT 只有一行。输出一个整数表示唯一路径的数量。

[编辑]SAMPLE INPUT (file betsy.in)

3

[编辑]SAMPLE OUTPUT (file betsy.out)

2

解题思路:

  1. 参考NOCOW“优化一”和“优化二”
  2. 自己的优化,在走到右边界或者下边界的时候,已走的路径将把正方形分为左右或者上下两个部分。如果右边或者上边有未访问的节点,这些点是访问不到的,直接剪枝

代码

/*
ID: zc.rene1
LANG: C
PROG: betsy
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_N 7

int N;
int visited[MAX_N + 1][MAX_N + 1];
int free_space[MAX_N + 1][MAX_N + 1];
int total_num;

void GetInput(FILE *fin)
{
    int i, j;

    fscanf(fin, "%d", &N);
    memset(visited, 0, (MAX_N + 1) * (MAX_N + 1) * sizeof(int));
    total_num = 0;

    for (i=1; i<=N; i++)
    {
	for (j=1; j<=N; j++)
	{
	    if (i == 1 || i == N || j == 1 || j == N)
	    {
		free_space[i][j] = 3;
	    }
	    else
	    {
		free_space[i][j] = 4;
	    }
	}
    }
    free_space[1][1] = 2;
    free_space[1][N] = 2;
    free_space[N][1] = 2;
    free_space[N][N] = 2;
}

int AllVisited(void)
{
    int i, j, count = 0;

    for (i=1; i<=N; i++)
    {
	for (j=1; j<=N; j++)
	{
	    if (visited[i][j] == 1)
	    {
		count++;
	    }
	}
    }
    
    if (count == N * N)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

int UDSeparate(void)
{
    int up_count = 0;
    int i, j;

    for (j=1; j<=N; j++)
    {
	i = 1;
	while (visited[i++][j] == 0)
	{
	    up_count++;
	}
    }

    if (up_count != 0)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

int LRSeparate(void)
{
    int right_count = 0;
    int i, j;

    for (i=1; i<=N; i++)
    {
	j = N;
	while (visited[i][j--] == 0)
	{
	    right_count++;
	}
    }

    if (right_count != 0)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

void SetFree(int i, int j, int k)
{
    if (i > 1)
    {
	free_space[i - 1][j] += k;
    }
    if (i < N)
    {
	free_space[i + 1][j] += k;
    }
    if (j > 1)
    {
	free_space[i][j - 1] += k;
    }
    if (j < N)
    {
	free_space[i][j + 1] += k;
    }
}

int FreeAround(int i, int j)
{
    int count = 0;

    if (i == N && j == 1)
    {
	return 0;
    }

    if (i > 1 && visited[i - 1][j] == 0)
    {
	count++;
    }
    if (i < N && visited[i + 1][j] == 0)
    {
	count++;
    }
    if (j > 1 && visited[i][j - 1] == 0)
    {
	count++;
    }
    if (j < N && visited[i][j + 1] == 0)
    {
	count++;
    }

    return count;
}


int CountFree(int i, int j, int *m, int *n)
{
    int count = 0;

    if (i > 1 && visited[i - 1][j] == 0 && free_space[i - 1][j] == 1)
    {
	if (i - 1 != N || j != 1)
	{
	    *m = -1;
	    *n = 0;
	    count++;
	}
    }
    if (i < N && visited[i + 1][j] == 0 && free_space[i + 1][j] == 1)
    {
	if (i + 1 != N || j != 1)
	{
	    *m = 1;
	    *n = 0;
	    count++;
	}
    }
    if (j > 1 && visited[i][j - 1] == 0 && free_space[i][j - 1] == 1)
    {
	if (i != N || j - 1 != 1)
	{
	    *m = 0;
	    *n = -1;
	    count++;
	}
    }
    if (j < N && visited[i][j + 1] == 0 && free_space[i][j + 1] == 1)
    {
	if (i != N || j + 1 != 1)
	{
	    *m = 0;
	    *n = 1;
	    count++;
	}
    }
    return count;
}

int DFS(int i, int j)
{
    int k, m, n;

    visited[i][j] = 1;
    SetFree(i, j, -1);

    if (i == N && j == 1)
    {
	if (AllVisited())
	{
	    total_num++;
	    visited[i][j] = 0;
	    SetFree(i, j, 1);
	    return ;
	}
	else
	{
	    visited[i][j] = 0;
	    SetFree(i, j, 1);
	    return ;
	}
    }

    if (i > 1 && i < N && j > 1 && j < N)
    {
	if (visited[i + 1][j] + visited[i - 1][j] == 2)
	{
	    if (visited[i][j + 1] + visited[i][j - 1] == 0)
	    {
		visited[i][j] = 0;
		SetFree(i, j, 1);
		return ;
	    }
	}
	if (visited[i][j + 1] + visited[i][j - 1] == 2)
	{
	    if (visited[i + 1][j] + visited[i - 1][j] == 0)
	    {
		visited[i][j] = 0;
		SetFree(i, j, 1);
		return ;
	    }
	}
    }

    if (j == N)
    {
	if (UDSeparate())
	{
	    visited[i][j] = 0;
	    SetFree(i, j, 1);
	    return ;
	}
    }
    if (i == N)
    {
	if (LRSeparate())
	{
	    visited[i][j] = 0;
	    SetFree(i, j, 1);
	    return ;
	}
    }

    k = CountFree(i, j, &m, &n); 

    if (k >= 2)
    {
	visited[i][j] = 0;
	SetFree(i, j, 1);
	return ;
    }
    else if (k == 1)
    {
	DFS(i + m, j + n);
    }
    else
    {
	if (i > 1 && visited[i - 1][j] == 0)
	{
	    DFS(i - 1, j);
	}
	if (i < N && visited[i + 1][j] == 0)
	{
	    DFS(i + 1, j);
	}
	if (j > 1 && visited[i][j - 1] == 0)
	{
	    DFS(i, j - 1);
	}
	if (j < N && visited[i][j + 1] == 0)
	{
	    DFS(i, j + 1);
	}
    }

    visited[i][j] = 0;
    SetFree(i, j, 1);
}

int main(void)
{
    FILE *fin, *fout;

    fin = fopen("betsy.in", "r");
    fout = fopen("betsy.out", "w");

    GetInput(fin);
    DFS(1, 1);
    fprintf(fout, "%d\n", total_num);

    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值