homework-04

 

编码规范

这次两个程序都是用c写的,我比较习惯的风格是main函数在最后,其他函数在前面,而zjoe习惯的编程风格是main函数在第一位,然后前面声明一堆变量。他阅读过一些工业级c的代码,据说很多用c写的库都用这样的风格。

我们两个人编写c语言都比较规范,重视代码的重用性。

当某一个功能重复次数打到3次以上的话,那么就比较有必要为之写一个函数。而模块化到底是不是都是好的呢?我觉得这是运行效率和代码可重用性的trade off,追求效率的代码会用很多小技巧来加速程序的运行,而其可重用行可扩展性就变低了。不过在现在这种程序员时间比机器时间还宝贵的时代,显然编写可重用的代码是要有益得多的。

时间记录

预计时间 5h 实际用时 7h
代码规范 0.0h   0.0h
具体设计 0.5h   1h
具体编码 3.5h   4h
代码复审 0.0h   0h
代码测试 0.5h   1h
测试报告 0.5h   0.5h

问题分析

new.c

对于如何构造一个wordsmatrix,我们一开始很难想到一种很好的构造方法,要想穷举所有的可能方法并寻找最优显然是不好写的,而且不一定能出结果。

经过我和我的peer的讨论,发现不妨换一种思路来考虑问题,不去漫无目的在状态空间里寻求最优解。而是限制状态空间(n*m),并且每次随机放单词,取一个估价最大的单词放上去,并且不进行回溯。

这样带来的一个问题是:不能保证每次都能得到解。不过只要把n和m设置得大一点,就能每次都得到解。

我们最后取了估价函数为:放置当前单词、当前位置、当前方向以后所能和以往单词相交的交点个数来作为当前动作的股价。显然我们希望单词之间交叉越多越好。

每次随机M次(程序里取了100000),每次找估价函数值最大的位置,方向。然后把单词放上去。

测试结果发现,例子sample.txt能在限制20*20的情况下构造出解来,而19*19就不行了。这个时候我们决定对单词长度进行排序,意外地发现程序在18*18的情况下构造出解来了。

最后经过分析发现,先放单词长的会更多地体现出估价函数的作用,而100000次随机使得这种股价效果异常明显。

最后对于sample.txt,我们得到上叙18*18的解。

至于如何填满,很容易,,直接填“X”估计就行,实在不行多随机几次就能把空填上(使用我写的test.c进行判断)

具体实现见代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <time.h>
  4 #define MAXNUM 100
  5 #define MAXLEN 26
  6 #define MAXMAT 100
  7 #define MAXRANDOM 100000
  8 int dx[8]={-1,-1,0,1,1,1,0,-1};
  9 int dy[8]={0,1,1,1,0,-1,-1,-1};
 10 int board[MAXMAT][MAXMAT];
 11 char words[MAXNUM][MAXLEN];
 12 int N,M;
 13 FILE *fin,*fout;
 14 void work(int n);
 15 int randpos(char *word, int *posx, int *posy, int *posd);
 16 int howgood(char *word, int x, int y, int drct);
 17 void placeword(char *word, int x, int y, int drct);
 18 void swap(char a[],char b[]);
 19 int main(int argc,char *argv[])
 20 {
 21     int n,i,j;
 22     fin=fopen("words.txt","r");
 23     fout=fopen("result.txt","w");
 24     fscanf(fin,"%d",&n);
 25     fprintf(fout,"%d\n",n);
 26     for(i=1;i<=n;i++)
 27     {
 28         fscanf(fin,"%s",words[i]);
 29         fprintf(fout,"%s\n",words[i]);
 30     }
 31     for(i=1;i<=n;i++)
 32         for(j=i+1;j<=n;j++)
 33         if(strlen(words[i])<strlen(words[j]))    
 34             swap(words[i],words[j]);
 35     N=atoi(argv[1]);
 36     M=atoi(argv[2]);
 37     work(n);
 38     
 39     for(i=1;i<=N;i++)
 40     {
 41         for(j=1;j<=M;j++)
 42             {
 43             printf("%c", board[i][j]);
 44             fprintf(fout,"%c",board[i][j]);
 45             }
 46         printf("\n");
 47         fprintf(fout,"\n");
 48     }
 49     return 0;
 50 }
 51 void swap(char a[],char b[])
 52 {
 53     int i; 
 54     char c;
 55     for(i = 0;i<MAXLEN;i++)
 56         {
 57         c=a[i];
 58         a[i]=b[i];
 59         b[i]=c;
 60         }
 61 }
 62 void work(int n)
 63 {
 64     int i,j,posx,posy,posd,can;
 65     for(i=1;i<=N;i++)for(j=1;j<=M;j++)board[i][j]=' ';
 66     srand((int)time(0));
 67     for(i=1;i<=n;i++)
 68     {
 69         can=randpos(words[i],&posx,&posy,&posd);
 70         if(can==-1)
 71         {
 72             printf("cannot!\n");
 73         //    getchar();
 74         }
 75         placeword(words[i],posx,posy,posd);
 76     }
 77 }
 78 int randpos(char *word, int *posx, int *posy, int *posd)
 79 {
 80     int max,i,x,y,d,temp;
 81     max=-1;
 82     for(i=1;i<=MAXRANDOM;i++)
 83     {
 84         x=rand()%N+1;
 85         y=rand()%M+1;
 86         d=rand()%8;
 87         temp=howgood(word,x,y,d);
 88         if(temp>max)
 89         {
 90             max=temp;
 91             *posx=x;
 92             *posy=y;
 93             *posd=d;
 94         }
 95     }
 96     return max;
 97 }
 98 int howgood(char *word, int x, int y, int drct)
 99 {
100     int xx,yy,score,i;
101     xx=x;
102     yy=y;
103     score=0;
104     for(i=0;i<strlen(word);i++)
105     {
106         if((xx<1 || xx>N || yy<1 || yy>M) || (board[xx][yy]!=' ' && board[xx][yy]!=word[i]))
107             return -1;
108         if(board[xx][yy]==word[i])
109             score++;
110         xx+=dx[drct];
111         yy+=dy[drct];
112     }
113     return score;    
114 }
115 void placeword(char *word, int x, int y, int drct)
116 {
117     int xx,yy,i;
118     xx=x;
119     yy=y;
120     for(i=0;i<strlen(word);i++)
121     {
122         board[xx][yy]=word[i];
123         xx+=dx[drct];
124         yy+=dy[drct];
125     }
126 } 
View Code

 

test.c

如何验证一个matrix是否满足条件1-3是一个很简单的p问题,最简单最暴力的是枚举8*n*m*(n+m)/2的子串,然后再和单词表进行比对,最后再判断一下是否四个角都填上了,是否有空行列。就能解决问题。

为了保证效率,我使用了Trie(单词查找树)进行匹配串。Trie是一种常用的数据结构,能够很好地实现字典查找。本质上也是一种Hash函数。

基本结构如下:

这么以来,查找的复杂度就变成了O(n*m),是一种比较高效的方法。

具体实现见代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #define MAXTREESIZE 2000
  4 #define MAXLEN 22
  5 #define MAXNUM 63
  6 #define MAXMAT 100
  7 
  8 struct Node
  9 {
 10     int flag;
 11     int p[26];
 12 };
 13 
 14 struct Go
 15 {
 16     int x;
 17     int y;
 18 };
 19 
 20 struct Node queue[MAXTREESIZE];
 21 struct Go pos[8] = {
 22 {0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}
 23 };
 24 /* 
 25  * note for *pos*
 26  * 0 is right
 27  * 1 is right down
 28  * 2 is down
 29  * 3 is ... you know
 30  * it is deasil(顺时针)
 31  *
 32  */
 33 char words[MAXNUM][MAXLEN],matrix[MAXMAT][MAXMAT],out[MAXMAT*2][MAXMAT*2];
 34 int numw,n,m,numnode,boo[MAXNUM];
 35 
 36 int ctoint(char c)
 37 {
 38     if (c >= 'a' && c<='z') return c-'a';
 39     if (c >= 'A' && c<='Z') return c-'A';
 40     return -1;
 41 }
 42 
 43 int newnode()
 44 {
 45     int i;
 46     queue[numnode].flag = -1;
 47     for(i = 0;i<26;i++)
 48         queue[numnode].p[i] = -1;
 49     numnode += 1;
 50     return numnode-1;
 51 }
 52 
 53 int insertnode(int flag,char s[])
 54 {
 55     int i,id = 0,cid;
 56     for(i = 0;i<strlen(s)-1;i++)
 57         {
 58         if (ctoint(s[i]) == -1)
 59             return -1;
 60         cid = queue[id].p[ctoint(s[i])];
 61         if (cid == -1)
 62             {
 63             cid = newnode();
 64             queue[id].p[ctoint(s[i])] = cid;
 65             }
 66         id = cid;
 67         }
 68     queue[id].flag = flag;
 69     return id;
 70 }
 71 
 72 int searchnode(int x,int y, int p)
 73 {
 74     int id = 0,cid;
 75     for(;x>=0&&y>=0&&x<n&&y<m; x+=pos[p].x,y+=pos[p].y)
 76         {
 77         cid = queue[id].p[ctoint(matrix[x][y])];
 78         if (cid == -1)
 79             return -1;
 80         id = cid;
 81         if (queue[id].flag != -1)
 82             return queue[id].flag;
 83         }
 84     return -1;
 85 }
 86 
 87 int testallword()
 88 {
 89     int i,j,p,k;
 90     for(i=0;i<n;i++)
 91         for(j=0;j<m;j++)    
 92             for(p=0;p<8;p++)
 93             {
 94                 k = searchnode(i,j,p);
 95                 if (k != -1)
 96                     {
 97                     //printf("%d %d %c %d %s",i,j,matrix[i][j],p,words[k]);
 98                     boo[k] += 1;
 99                     }
100             }
101     for(i=0;i<numw;i++)
102         {
103         //printf("%d\n",boo[i]);
104         if (boo[i]==0)
105             return -1;
106         }
107     return 0;
108 }
109 
110 void addtag(int x,int y,int p,int k)
111 {
112     int i,g;
113     char c;
114     for(i = 0;i < strlen(words[k])-2;i++)
115         {
116         if (p == 0 || p == 4) c = '-';
117         if (p == 1 || p == 5) c = '\\';
118         if (p == 2 || p == 6) c = '|';
119         if (p == 3 || p == 7) c = '/';
120         out[2*x + pos[p].x][2*y + pos[p].y] = c;
121         x += pos[p].x;
122         y += pos[p].y;
123         }
124     return ;
125 }
126 
127 void outans()
128 {
129     int i,j,p,k;
130     for(i=0;i<n;i++)
131         for(j=0;j<m;j++)
132             {
133             out[i*2][j*2] = matrix[i][j];
134             out[i*2+1][j*2] = ' ' ;
135             out[i*2][j*2+1] = ' ' ;
136             out[i*2+1][j*2+1] = ' ' ;
137             }
138     for(i=0;i<n;i++)
139         for(j=0;j<m;j++)
140             for(p=0;p<8;p++)
141             {
142                 k = searchnode(i,j,p);
143                 if(k!=-1)
144                     addtag(i,j,p,k);
145             }
146     for(i=0;i<n*2-1;i++)
147         printf("\t%s\n",out[i]);
148 }
149 
150 int testcorner()
151 {
152     if(out[0][1]==' ' && out[1][0]==' ' && out[1][1]==' ')
153         return -1;
154     if(out[2*n-1][0]==' ' && out[2*n][1]==' ' && out[2*n-1][1]==' ')
155         return -1;
156     if(out[0][2*m-1]==' ' && out[1][2*m]==' ' && out[1][2*m-1]==' ')
157         return -1;
158     if(out[2*n-1][2*m]==' ' && out[2*n][2*m-1]==' ' && out[2*n-1][2*m-1]==' ')
159         return -1;
160     return 0;
161 }
162 
163 int main(int argc,char *argv[])
164 {
165     int i,j;
166     if (argc == 1)
167     {
168         freopen("sample.txt","r",stdin);
169     }
170     if (argc >=2)
171     {
172         if(freopen(argv[1],"r",stdin)==NULL)
173             {
174             printf("please input the corrent <file name>\n");
175             return -1;
176             }
177     }
178     if (argc >=3)
179     {
180         freopen(argv[2],"w",stdout);
181     }
182 
183     scanf("%d\n",&numw);
184     newnode();
185     for(i = 0; i<numw;i++)
186         {
187         fgets(words[i],MAXLEN,stdin);
188         if ((j = insertnode(i,words[i]))==-1)
189             return -1;
190         }
191     while(fgets(matrix[n],MAXMAT,stdin)>0)
192         n += 1; 
193     m = strlen(matrix[0])-1;
194 
195     if(testallword()==0)
196         {
197         printf("STATE1:\tis good!\n");
198         outans();
199         }
200     else
201         {
202         printf("STATE1:\tbad!\n");
203         printf("\tYou leave the words belove(no used or used more than once):\n");
204         for(i=0;i<numw;i++)
205             if(boo[i]!=1)
206                 printf("\tused times = %d , %s",boo[i],words[i]);
207         }
208     if(n==m)
209         printf("\nSTATE2:\tis good! n&m = %d\n",n);
210     else 
211         printf("\nSTATE2:\tbad! n=%d m=%d\n",n,m);
212     if(testcorner() == 0)
213         printf("\nSTATE3:\tis good!\n");
214     else
215         printf("\nSTATE3:\tbad!\n");
216     return 0;
217 }
View Code

 

WordsSearch生成,验证工具说明

new.c :读入words.txt 生成 result.txt

test.c :读入(默认读入sample.txt 需要指定参数伟result.txt) 屏幕生成测试结果说明

words.txt :第一行一个整数n,表示以下有n行单词

result.txt :new生成的结果,第一行一个整数n,以下n行单词,最后输出一个矩阵

sample.txt :老师网站上的例子

new :new.c的可执行文件(under linux)

new.c使用方法

gcc new.c -o new

./new 18 18 #生成18*18的结果矩阵(有很小的几率出错)

目前可以生成的最优矩阵为18*18

K MXUNIL      OFAQ
 SPEYELIMSURIVPOU 
 AI DOCUMENT  ENS 
 VHDROWSSAPPRINTER
TECCAPMENUFREEWARE
BRSCOOINOCITOME NR
 SOUBLIMULTIMEDIAA
CPUPYFCYBERSPACEMW
Y NLEASBUGO SDRWEY
  DOKRAQTBJ O EPLP
 TCAIEICPEAWIBVOIS
 OADTTUPNINNB RTFW
 OR EAU HLHRD EKPO
JBDN HBLOEOAEWSSID
PEHSARCAOWRVCHIEZN
EREVIRDASSSA KTD I
GIGABYTECEEJL EETW
FIREWIRE  ERAWDRAH

test  result from my test.c

STATE1: is good!
K   M X-U-N-I-L             O F-A-Q 
 \   \       /              | |     
  S P E Y-E-L-I-M-S-U-R-I-V P O U   
  |\|  \   /                | | |   
  A I   D-O-C-U-M-E-N-T     E N S   
  | |\  |/                  | | |   
  V H D-R-O-W-S-S-A-P P-R-I-N-T-E-R 
  | |  /|  \                    |   
T E C C A P M-E-N-U F-R-E-E-W-A-R-E 
 \   /  | |            /        | | 
B R S C O O I N-O-C-I-T-O-M-E   N R 
 \ \|/  | | |        /          | | 
  S O U B L I M-U-L-T-I-M-E-D-I-A A 
   \|\| | | |      /|           | | 
C-P-U P Y F C-Y-B-E-R-S-P-A-C-E M W 
 /  | |\| | |    /  |           | | 
Y   N L E A S B-U-G O   S D R W E Y 
    |\| |\| |  /    |   |/  |/  | | 
    D O K R A Q T B J   O   E P L P 
    |\|\  |\ /   \ \|  /|  /| | | | 
  T C A I E I-C-P E A W I B V O I S 
  | | |\ \|/ \     \|\  |/  | | | | 
  O A D T T-U-P-N-I N N B   R T F W 
  | |    / \   \   /|\ \    | | | | 
  O R   E A U   H L H R D   E K P O 
  | |  / \ \ \   /  |\ \ \  | | | | 
J B D N   H B L O E O A E W S S I D 
| |        \ \ \   /| |\ \ \  | | | 
P E H-S-A-R-C A O W R V C H I E Z N 
| |          \ \ \  |\|  \ \ \|   | 
E R-E-V-I-R-D A S S S A   K T D   I 
|              \ \ \| |\   \ \ \  | 
G-I-G-A-B-Y-T-E C E E J L   E E T W 
             /       \       \   \  
F-I-R-E-W-I-R-E     E-R-A-W-D-R-A-H 

STATE2: is good! n&m = 18

STATE3: is good!

test.c使用方法

输出结果显示是否满足1,2,3条件

1、每个单词只出现且必须出现一次、没空行空列
2、长宽必须一样
3、四个角必须被单词包含

 

posted @ 2013-10-27 22:58  Forwil  阅读(471)  评论(0编辑  收藏  举报