一、问题描述
本次作业的题目要求利用给定的一组单词生成一个矩阵,矩阵的每个位置由一个字母填充,单词表中的每一个单词可以匹配矩阵中一段连续的序列,这段序列可以是横向,纵向或者是45度斜角方向,单词可以由左向右匹配,也可以逆向匹配。题目将生成的矩阵分为3个等级,任意一个等级要求满足前一级所有要求。第一级要求每个方向上至少出现两个单词,总共四个方向,矩阵横纵规模可以不等,每个单词在矩阵中仅能被覆盖一次,不能存在一行或一列不被任何短语覆盖;第二级要求矩阵横纵相等;第三级要求四个角必须被覆盖。最后返回的矩阵期望能有尽可能小的规模。
二、问题分析
1. 每个单词在矩阵中出现,且只出现1次 2. 上下、下上、左右、右左及对角线共8个方向,每个方向均不少于2个单词排布。 3. 矩阵长宽可以不同 4. 不存在无效行或列 5. (进阶要求)矩阵为正方形 6. (进阶要求)矩阵四角有单词覆盖
我们讨论出的解题思路是枚举+暴力搜索。再进行一部分优化。
三、解题思路
我们的思想是直接做矩阵为正方形的这种情况。因为之前又一次上课我们已经讨论过这道题。
我们的思路是
1.首先把所有的单词按长度由大到小排列
2.8个不同方向我们分别用向量 水平左(-1,0),斜左上(-1,1),竖直上(0,1),斜右上(1,1),水平右(1,0),斜右下(1,-1),竖直下(0,-1),斜左下(-1,-1),
3.然后从字符长度最长的单词开始往里加入。每一次加入时给该单词的第一个位置随机生成一个(x,y),还有一个单词的方向 direct,随机生成很多次,然后就是计算这里得分最高的一组,在result—array的(x,y)处放置该单词的第一个字母,然后按照放置方向direct将该单词全部放入。
4、那么我们的分数是怎么计算的呢,我们的思路是这样的,如果放置的位置已经有了要放置的字母,那么这么放该字母的效率就非常高,所以就加一分。
四、源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
#define maxtry 100000
int totalnum=0;
char phrase_array[100][100];
char result_array[100][100];
int DX[8]={-1,-1,0,1,1,1,0,-1};
int DY[8]={0,1,1,1,0,-1,-1,-1};
void sort()
{
int i,j;
char s[100];
for(i=1;i<=totalnum;i++)
for(j=i+1;j<=totalnum;j++)
if(strlen(phrase_array[i])<strlen(phrase_array[j])){
strcpy(s,phrase_array[i]);
strcpy(phrase_array[i],phrase_array[j]);
strcpy(phrase_array[j],s);
}
}
void input(FILE **p)
{
int i=0,j;
while(fscanf(*p,"%s",phrase_array[++totalnum])!=-1);
totalnum--;
sort();
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
result_array[i][j]=' ';
}
void insertword(char *phrase,int location_x,int location_y,int location_d)
{
int i;
for(i=0;i<strlen(phrase);i++)
{
result_array[location_x][location_y]=phrase[i];
location_x+=DX[location_d];
location_y+=DY[location_d];
}
}
int calculate(char *phrase,int x,int y,int d)
{
int i,score=0;
for(i=0;i<strlen(phrase);i++)
{
if(x>N||x<1||y>N||y<1)
return -1;
else if(phrase[i]==result_array[x][y])
score++;
else if(result_array[x][y]!=' ')
return -1;
x+=DX[d];
y+=DY[d];
}
}
int locateofrand(char *phrase,int *location_x,int *location_y,int *location_d)
{
int best=-1;
int i,x,y,d,temp;
for(i=1;i<=maxtry;i++)
{
x=rand()%N+1;
y=rand()%N+1;
d=rand()%8;
temp=calculate(phrase,x,y,d);
if(temp>best)
{
best=temp;
*location_x=x;
*location_y=y;
*location_d=d;
}
}
return best;
}
void workprocess()
{
int location_x,location_y,location_d,i,j,judge;
srand((int)time(0));
for(i=1;i<=totalnum;i++){
judge=locateofrand(phrase_array[i],&location_x,&location_y,&location_d);
if(judge==-1){
printf("please change the value of N!\n");
}
insertword(phrase_array[i],location_x,location_y,location_d);
}
}
void output(FILE **p)
{
int i,j;
for(i=1;i<=N;i++){
for(j=1;j<=N;j++)
fprintf(*p,"%c",result_array[i][j]);
fprintf(*p,"\n");
}
}
int main(int argc, char *argv[])
{
FILE *in,*out;
in=fopen("input.txt","r");
out=fopen("result.txt","w");
input(&in);
workprocess();
output(&out);
return 0;
}
五、总结
在这次的编程过程中,我们相互促进,共同学习讨论算法,完善判断思路与分数计算条件,虽然最终得出的搜索算法远远不能说是完成所有的要求和效率最高,但是我们已然完成了题目的要求,即8方向,无重复,四角有单词,矩阵最小。与此同时,我们的团队效率也较上次大大提升,面对后续的作业,我们充满信心~!
六、报告
Personal Software Process Stages | 时间百分比(%) | 实际花费的时间 (分钟) | 原来估计的时间 (分钟) |
计划 | 10% | 180 | 120 |
· 估计这个任务需要多少时间,把工作细化并大致排序 | 10% | 180 | 120 |
开发 | 85% | 1530 | 1020 |
· 需求分析 (包括学习新技术) | 15% | 270 | 180 |
· 设计复审 (和同事审核设计文档) | 10% | 180 | 120 |
· 代码规范 (制定合适的规范) | 5% | 90 | 60 |
· 具体设计 | 10% | 180 | 120 |
· 具体编码 | 35% | 630 | 420 |
· 代码复审 | 5% | 90 | 60 |
· 测试(自我测试,修改代码,提交修改) | 5% | 90 | 60 |
总结报告 | 5% | 90 | 60 |
总计 | 100% | 总用时 1800 | 总估计的用时 1200 |