Wisconsin Squares

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

描述

威斯康星州的春天来了,是该把小奶牛们赶到小牧场上并把大奶牛们赶到北纬 40 度的大牧场上的时候了。

农夫约翰的牧场上有五种奶牛(括号内的是缩写):格恩西奶牛(A),泽西奶牛(B),赫里福奶牛(C),黑安格斯奶牛(D),朗赫恩奶牛(E)。这些奶牛群放养在一片 16 英亩的牧场上,每英亩上都有一小群奶牛,像下面这样排列成 4 x 4 的格子(用行和列标号):

  1 2 3 4
 +-------
1|A B A C
2|D C D E
3|B E B C
4|C A D E

最初,牧场上的奶牛群总共有 3 群 A,3 群 B,4 群 C,3 群 D,3 群 E。今年的 D 种小奶牛比去年多一群 ,C 种少一群,共有 3 群 A,3 群 B,3 群 C,4 群 D,3 群 E。

农夫约翰对于他牧场上的奶牛群的布局非常小心。这是因为如果同一种类型的奶牛群靠得太近,她们就乱来:她们聚集在栅栏边上抽烟,喝牛奶。如果她们在相同的格子上或者在临近的 8 个格子上,就是靠得太近了。

农夫约翰得用他的棕色旧福特皮卡把他的大奶牛群运出牧场,并把他的小奶牛群运进牧场,皮卡一次只能运一群奶牛。他装上一群小奶牛,开车到小牧场的一个方格中,卸下这群小奶牛,再装上这个格子上的那群大奶牛,开到北纬 40 度的大牧场卸下来。他重复这样的操作 16 次,然后开车去杰克商店办理低脂酸奶的交易和家居装修。

帮助农夫约翰。他必须选择正确的顺序来替换他的奶牛群,使得他从不把一群小奶牛放入当前被同样类型奶牛占有的方格或者当前被同样类型奶牛占据的方格的临近方格。当然,一旦大奶牛走了,小奶牛就被安置好(in place),他必须小心以后的情况,要根据新的排列把奶牛群分开。

非常重要的提示:农夫约翰从过去的经验知道,他必须先移动 D 种奶牛群。

找出农夫约翰将他的小奶牛搬迁到她们的新牧场上的办法。输出 16 个连续的 奶牛群类型/行/列 的信息,使得这样的安排能够符合安全经验。

计算 4 x 4 牧场的最终操作方案总数并输出其中一种方案。

[编辑]格式

TIME LIMIT: 5秒

PROGRAM NAME: wissqu

INPUT FORMAT

四行,每行四个字母,表示奶牛群。

OUTPUT FORMAT

16 行,每行分别由 奶牛群类型/行/列组成。如果有多解(一定有),那么你应该输出奶牛群类型按照字典序排列在最前面的那个解。如果不只一个解满足条件,那么你应该输出行信息按照字典序排列在最前面的那个解。如果仍然不只一个解满足条件,那么你应该输出列信息按照字典序排列在最前面的那个解。

最后多输出一行,所有可能的操作方案总数。

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

ABAC
DCDE
BEBC
CADE


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

D 4 1
C 4 2
A 3 1
A 3 3
B 2 4
B 3 2
B 4 4
E 2 1
E 2 3
D 1 4
D 2 2
C 1 1
C 1 3
A 1 2
E 4 3
D 3 4
14925


解题思路:

  1. 用around[i][j][k] = m记录i行j列这个网格以及其周围8个相邻网格中k种牛的总数为m(ABCDE分别对应12345),那么around[i][j][k] = 0时,(i, j)可以放置k种牛。记得在DFS过程中移入和移出的时候要更新9个网格的around值
  2. 用cow_num[i] = j记录i种牛的剩余个数为j,初始均为3
  3. 用DFS来遍历放置的方式,特殊处理第一个放的D。然后放置第n头牛的时候首先选择牛的种类(从A到E),然后选择放置的格子(从上到下,从左到右),更改相应的变量,并放置下一头牛,直到放置完最后一头牛。DFS返回的时候记得恢复更改的变量
  4. 在DFS过程中保存第一个满足条件的放置方式即可

代码

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

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

int matrix[6][6];
int around[6][6][6];
int cow_num[6] = {0, 3, 3, 3, 3, 3};
int placed[6][6];
int total_num = 0;
int route[17][3];

void GetInput(FILE *fin)
{
    int i, j, m, n;
    char c;

    memset(matrix, -1, 6 * 6 * sizeof(int));
    memset(around, 0, 6 * 6 * 6 * sizeof(int));

    for (i=1; i<=4; i++)
    {
	for (j=1; j<=4; j++)
	{
	    fscanf(fin, "%c", &c);
	    matrix[i][j] = c - 'A' + 1;
	    for (m=-1; m<=1; m++)
	    {
		for (n=-1; n<=1; n++)
		{
		    around[i+m][j+n][matrix[i][j]]++;
		}
	    }
	}
	fscanf(fin, "%c", &c);
    }
}


void AddNeighbour(int i, int j, int k)
{
    int m, n;

    for (m=-1; m<=1; m++)
    {
	for (n=-1; n<=1; n++)
	{
	    around[i+m][j+n][k]++;
	}
    }
}

void MinusNeighbour(int i, int j, int k)
{
    int m, n;

    for (m=-1; m<=1; m++)
    {
	for (n=-1; n<=1; n++)
	{
	    around[i+m][j+n][k]--;
	}
    }
}


void PlaceTheOthers(int index)
{
    int i, j, k, cp;

    if (index == 17)
    {
	total_num++;
	return ;
    }

    for (i=1; i<=5; i++)
    {
	if (cow_num[i] > 0)
	{
	    for (j=1; j<=4; j++)
	    {
		for (k=1; k<=4; k++)
		{
		    if (placed[j][k] == 0 && around[j][k][i] == 0)
		    {
			cow_num[i]--;
			cp = matrix[j][k];
			MinusNeighbour(j, k, cp);
			matrix[j][k] = i;
			placed[j][k] = 1;
			AddNeighbour(j, k, i);

			if (total_num == 0)
			{
			    route[index][0] = i;
			    route[index][1] = j;
			    route[index][2] = k;
			}

			PlaceTheOthers(index + 1);

			MinusNeighbour(j, k, i);
			placed[j][k] = 0;
			matrix[j][k] = cp;
			AddNeighbour(j, k, cp);
			cow_num[i]++;
		    }
		}
	    }
	}
    }
}

void BeginToPlace(void)
{
    int i, j, cp;

    memset(placed, 0, 6 * 6 * sizeof(int));
    /*place D*/
    for (i=1; i<=4; i++)
    {
	for (j=1; j<=4; j++)
	{
	    if (around[i][j][4] == 0)
	    {
		cp = matrix[i][j];
		matrix[i][j] = 4;
		MinusNeighbour(i, j, cp);
		placed[i][j] = 1;
		AddNeighbour(i, j, 4);

		if (total_num == 0)
		{
		    route[1][0] = 4;
		    route[1][1] = i;
		    route[1][2] = j;
		}
		PlaceTheOthers(2);

		MinusNeighbour(i, j, 4);
		placed[i][j] = 0;
		AddNeighbour(i, j, cp);
		matrix[i][j] = cp;
	    }
	}
    }
}

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

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

    GetInput(fin);
    BeginToPlace();

    for (i=1; i<=16; i++)
    {
	fprintf(fout, "%c %d %d\n", route[i][0] + 'A' - 1, route[i][1], route[i][2]);
    }
    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、付费专栏及课程。

余额充值