2000.11请你编程
美食家俱乐部程序的基本思路是:
1.定义四个数组:
int one[16]; //标示16个人是否已安排好,0表示还未安排好,1表示已安排好。
int two[16][16]; //记录任意两者是否已同过一桌。
int three[16][16][16];//记录任意三者是否已同过一桌。
int four[16][16][16][16];//记录任意四者是否已同过一桌。
2.读出文件gourmet.txt中的数据,初始化数组two、three、four;
3.产生一个当天未上桌的人a;
4.产生第二个当天未上桌的人b;
5.判断是否a、b还未同过桌,若同过则重做4;
6.同理产生c、d;
7.如果可以产生,则记录到数组,输出并保存;否则输出不可产生排序法,退出。
本程序由:VC6.0编成,DOS环境下执行通过。
源程序如下:
// 排人.cpp : Defines the entry point for the application.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int one[16]; //标识16个人是否已安排好,0表示还未安排好,1表示已安排好。
int two[16][16]; //记录任意两者是否已同过一桌。
int three[16][16][16]; //记录任意三者是否已同过一桌。
int four[16][16][16][16];//记录任意四者是否已同过一桌。
int num=0; //计数器,输出格式用
void definevalue(int a,int b,int c,int d) //复值函数,将已同过一桌的人的对应数组置1。
{
two[a][b]=1;
two[b][c]=1;
two[c][d]=1;
two[a][c]=1;
two[a][d]=1;
two[b][d]=1;
three[a][b][c]=1;
three[a][b][d]=1;
three[a][c][d]=1;
three[b][c][d]=1;
four[a][b][c][d]=1;
}
void output(int a,int b,int c,int d,int out_count) //输出函数,将算出的值在屏幕上显示,并存盘。
{
FILE *fp;
printf(″%c%c%c%c″,a+65,b+65,c+65,d+65);
if(num%4==3)
printf(″\n″);
else printf(″\t″);
if((fp=fopen(″gourmet.txt″, ″r+″))==NULL)
{
printf(″File of gouret.txt is not opened.\n″);
exit(1);
}
fseek(fp,0,SEEK_END);
if(num%4==0)
fprintf(fp,″\n″);
else
fprintf(fp,″ ″);
fprintf(fp,″%c%c%c%c″,a+65,b+65,c+65,d+65);
fclose(fp);
num++;
}
void init() //初始化函数,用于清零四个数组。
{
int i,j,k,l;
for (i=0;i<13;i++)
{
one[i]=0;
for(j=1;j<14&&j!=i&&i<j;j++)
{
two[i][j]=0;
for(k=2;k<15&&k!=j&&k!=i&&j<k;k++)
{
three[i][j][k]=0;
for(l=3;l<16&&l!=i&&l!=j&&l!=k&&k<l;l++)
four[i][j][k][l]=0;
}
}}}
void readfile() //读文件函数,用于将已给数据读出。
{
int i,a=0,b=0,c=0,d=0;
FILE *fp;
if((fp=fopen(″gourmet.txt″, ″r″))==NULL)
{
printf(″File of gouret.txt is not opened.\n″);
exit(1);
}
for(i=0;i<12;i++)
{fseek(fp, (i*5)+int(i/4), SEEK_SET);
fscanf(fp, ″%c%c%c%c″, &a,&b,&c,&d);
definevalue(a-65,b-65,c-65,d-65);}
fclose(fp);}
int produce(int first) //从当天还未在桌上吃饭的人中选人。
{
int e=0,i;
for(i=first;i<16;i++)
{if(one[i]==0)
{e=i;
return(e); //选中。
}}
return(-1); //无人可选。
}
void table(int first,int tab_count) //产生一桌四个人。
{ int a,b,c,d;
b=a=produce(first); //从first开始产生第一个人,第二个人记住。
do
{do
{c=b=produce(b+1); //从第一个人开始产生第二个人,第三个人记住。
if(b==-1) //如果不能产生第二个人则报不能排,退出。
{ printf(″\nIt is not possible to complete this schedule.\n″);
getch();
exit(1);}
}
while(two[a][b]==1); //产生的第二个人已经和第一个人同桌过。
do
{do
{d=c=produce(c+1); //从第二个人开始产生第三个人,第四个人记住。}
while((c!=-1)&&(three[a][b][c]==1||two[a][c]==1||two[b][c]==1)); //产生的第三个人已经和第二或第一个人同桌过。
do
{ d=produce(d+1); //从第三个人开始产生第四个人,}
while((c!=-1)&&(d!=-1)&&(four[a][b][c][d]==1||two[a][d]==1||two[b][d]==1||two[c][d]==1||three[a][b][d]==1||three[a][c][d]==1||three[b][c][d]==1));
//产生的第四个人已经和第三、第二或第一个人同桌过。}
while((c!=-1)&&(d==-1));}
while(c==-1);
one[a]=1; //标志已排好的四人上过桌。
one[b]=1;
one[c]=1;
one[d]=1;
definevalue(a,b,c,d);
output(a,b,c,d,tab_count);}
void calculate(int cal_count) //计算排序的调用次数。
{int i;
for(i=0;i<13;i++)
if(!one[i])
table(i,cal_count);}
void day(int date) //可以在此处通过修改参数达到算出不同天数的排序。
{int count;
count=(date+3)*4;
calculate(count); }
void main()
{int date,i;
init();
readfile();
for(date=0;date<2;date++)
{num=0;
day(date);
for(i=0;i<16;i++)
one[i]=0;}
getch();}
本期请你编程题目
动物园要把M只狼和N只狗(N>=M)从一条河的西岸送到河的东岸。只有一条小船可以送它们过去。但是,这条船一次最多只能坐2只动物,最少必须要坐1只动物。但是,由于狗比较弱小,当某一边岸上的狗的数目少于狼的数目(如果狗的数目不为零的话)的时候,狼就会欺负狗。所以,在运送的过程中必须保持两边岸上狗的数目都不少于狼的数目。我们现在利用两个m、n和一个字母P表示运送过程中每一步骤的状态:m、n表示该步骤中在西岸上狼和狗的数目,字母P可以取两个值(W、E),W表示该步骤中船在西岸、E表示该步骤中船在东岸。作为初始状态,可以表示为(M,N,W)。
很明显,假设一开始有2只狼、2只狗,船在西岸,这时候状态表示为(2,2,W),如果把2只狼运送过去,则下一步状态为西岸上没有狼,只有2只狗,船在东岸,表示为(0,2,E)。当最后状态演变成为(0,0,E)的时候,就可以认为全部运送成功。当最后状态无法演变成为(0,0,E)的时候,可以认为这是一个无法完成的任务。现在就请你编一个程序来帮动物园解决这个问题。程序要求如下:
输入:输入数据从文本文件zoo.txt中读取,格式为若干行,每行包括两个整数M、N,表示有M只狼和N只狗,(10>=N>=M>=1),两数之间用空格分开。当M=N=0的时候,表示输入数据结束。
输出:输出到屏幕上,对于某一组输入数据M、N,如果不可能运送成功,输出字符串:“不可能的任务”。否则按每步(m,n,P)的格式输出运送过程中每步状态,m、n表示该步步骤中在西岸上狼和狗的数目,字母P可以取两个值(W、E),W表示该步步骤中船在西岸、E表示该步步骤中船在东岸,每步状态输出一行。一组数据输出完毕后输出一空行与下一组输出数据分开。
输入范例:
2 2
0 0
输出范例:
(2,2,W)
(0,2,E)
(1,2,W)
(1,0,E)
(2,0,W)
(0,0,E)
本期题目由上海的oldbug提供。