算法竞赛入门经典(第2版)第4章 函数和递归
例题4-5 追踪电子表格中的单元格 UVa512
感悟。
1、阅读书中题目,从网站下载英文原题,重点在看输出数据与格式,叙述过程太繁琐,没耐心看下去。
2、立马打开Excel模拟了一遍,看懂题意了。
3、理解如下:数据输入输出流程,先定row,col;数据操作:增删改;数据查询,查询输出,完整的一轮表格处理结束。
3、写代码时,先把功能框架搭起来,一个功能一个功能的写,同时也一个功能一个功能的输出,大大提高了代码的成功率,同时也代码跨度时间也有两天。
4、冒泡排序,插入排序的类似算法用了许多,可见基础的重要。
5、写好代码,156行,觉得有些冗余,到达一定水平后,应能控制在80行以内,测试数据通过,提交Wrong answer。
6、准备翻看书本,估计还是输入输出的理解上有差异。
7、直接看书中代码主函数main部分,结合原题,发现Separate output from different spreadsheets with a blank line.没考虑到,修改,提交Wrong answer.
8、翻看http://blog.csdn.net/thudaliangrx/article/details/50700688也是WA,重回书本,看看该怎么改。
9、像一个好学生一样,不停对照书中代码的输出与本人代码的输出,一模一样,怎么会一直WA。
10、偶然一试越界的情况,差异马上就出来了,本人代码的鲁棒性(健壮性)不够,对付越界删除插入有问题。
如图
书中代码数据输入输出,如下图:
本人代码数据输入输出,如下图:
大家看出差别了吗。
11、开始增强鲁棒性(健壮性), 提交WA,傻了。
12、有没有可能是没有初始化,引起的错误,马上加上memset(cell,0,sizeof(cell));提交WA。
13、刷新了两个小时,才看到结果,AC,此刻已是2016年8月16日10点16分,激动人心的一刻,等得太久了。
14、怎么AC啦,各位看官请听我慢慢道来。
15、经历了12条,已经准备放弃了,但还是不甘心啊,按照书本思路,改进了核心代码处理部分,但输入输出部分还是保持原来的编码,提交WA。
16、那只能是输入输出部分出问题,书本程序,自个编写程序在程序运行后,对比了输入输出,完全一样啊。
17、直接对照书本程序,自个编写程序输入输出部分的源代码,不经意间看到一句,
马上改成:
提交AC,多出的%,看输出结果是看不到的,只有查源代码,这个错误怎么纠正,没办法,只有读源代码,太难啦。
18、开始改最开始的程序,看看提交的结果,需要考虑11条吗?提交WA。看来要考虑鲁棒性(健壮性)。
19、提交11条鲁棒性(健壮性)对应的代码,提交WA。
20、AC代码为参考书中思想编写。
21、采用同种功能进行替换的办法,将提交AC中的功能用有问题的代码中的功能进行一一替换,提交,发现有问题代码中的插入行,插入列,交换数据,输出数据功能AC,删除行,删除列,WA,这样就把精力集中在这两个功能上,待会,好好研读代码,看是否能将这两个功能AC。又发现了一个排错的好办法,在没有足够的输入输出测试数据情况下。
22、经过排查,发现本人代码只适合先删除后插入,若是先插入后删除,则输出数据错误。
修改前局部代码:
修改后局部代码:
23、至此按自个思想编写的程序终于AC了。
24、验证11条健壮性,发现不考虑,提交就WA。
25、附上AC代码,基本上是自个思想的代码。
26、查看UVa网站记录,一共提交28次,至此此题宣告攻克,时间2016年8月17日21:29。
附上代码
环境Dev-cpp4.9.9.2
#include <stdio.h>
#include <string.h>
struct node{
int r;
int c;
};
struct node cell[100][100];
void printcell(int r,int c){//打印cell数据,测试用
int i,j;
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
printf("%d,%d ",cell[i][j].r,cell[i][j].c);
}
printf("\n");
}
}
int main(){
int r,c,n,i,A,j,k,l,t,r1,c1,r2,c2,kase,m;
char cmd[20];
int a[20];
struct node tmpcell;
kase=0;
while(scanf("%d%d",&r,&c)==2&&r&&c){
memset(cell,0,sizeof(cell));//结构体也可以memset,初始化为0
for(i=1;i<=r;i++)//根据行列初始化表格
for(j=1;j<=c;j++){
cell[i][j].r=i;
cell[i][j].c=j;
}
scanf("%d",&n);//增删改
for(i=0;i<n;i++){
scanf("%s",cmd);
if(strcmp(cmd,"DR")==0){//删除行
scanf("%d",&A);
memset(a,0,sizeof(a));
k=0;
for(j=0;j<A;j++){
scanf("%d",&t);
if(t>=1&&t<=r)//健壮性,保证删除行在表格数据范围内
a[k++]=t;
}
A=k;
for(j=0;j<A;j++)//将要删除行,标记数据为0
for(k=1;k<=c;k++){
cell[a[j]][k].r=0;
cell[a[j]][k].c=0;
}
for(j=0;j<A;j++)//自小到大排序
for(k=j+1;k<A;k++){
if(a[j]>a[k]){
t=a[j];
a[j]=a[k];
a[k]=t;
}
}
for(l=0;l<A;l++)//类似冒泡排序
for(j=1;j<=r;j++){
if(j==a[l]){//整行的处理。
for(m=j;m<=r-1;m++)
for(k=1;k<=c;k++){
tmpcell=cell[m][k];
cell[m][k]=cell[m+1][k];
cell[m+1][k]=tmpcell;
}
for(k=0;k<A;k++)//删除一行后,a[]数组中的值整体-1
a[k]--;
}
}
r-=A;//将总行数更新
}else if(strcmp(cmd,"DC")==0){//删除列
scanf("%d",&A);
memset(a,0,sizeof(a));
k=0;
for(j=0;j<A;j++){
scanf("%d",&t);
if(t>=1&&t<=c)
a[k++]=t;
}
A=k;
for(j=0;j<A;j++)
for(k=1;k<=c;k++){
cell[k][a[j]].r=0;
cell[k][a[j]].c=0;
}
for(j=0;j<A;j++)
for(k=j+1;k<A;k++){
if(a[j]>a[k]){
t=a[j];
a[j]=a[k];
a[k]=t;
}
}
for(l=0;l<A;l++)//类似冒泡排序
for(j=1;j<=c;j++){
if(j==a[l]){//整行的处理。
for(m=j;m<=c-1;m++)
for(k=1;k<=r;k++){
tmpcell=cell[k][m];
cell[k][m]=cell[k][m+1];
cell[k][m+1]=tmpcell;
}
for(k=0;k<A;k++)//删除一列后,a[]数组中的值整体-1
a[k]--;
}
}
c-=A;//将总行数更新
}else if(strcmp(cmd,"IR")==0){//插入行
scanf("%d",&A);
memset(a,0,sizeof(a));
for(j=0;j<A;j++){
scanf("%d",&a[j]);
}
for(j=0;j<A;j++){//冒泡排序,自小到大
for(k=j+1;k<A;k++){
if(a[j]>a[k]){
t=a[j];
a[j]=a[k];
a[k]=t;
}
}
}
for(j=0;j<A;j++)//查询是否越界
if(a[j]>r)
break;
if(j<A)//越界处理,A值变小
A=j;
for(l=0;l<A;l++){
for(j=r;j>=a[l]+l;j--){//插入行
for(k=1;k<=c;k++){
cell[j+1][k].r=cell[j][k].r;
cell[j+1][k].c=cell[j][k].c;
}
}
for(k=1;k<=c;k++){
cell[a[l]+l][k].r=0;
cell[a[l]+l][k].c=0;
}
r+=1;
}
}else if(strcmp(cmd,"IC")==0){//插入列
scanf("%d",&A);
memset(a,0,sizeof(a));
for(j=0;j<A;j++){
scanf("%d",&a[j]);
}
for(j=0;j<A;j++){//冒泡排序,自小到大
for(k=j+1;k<A;k++){
if(a[j]>a[k]){
t=a[j];
a[j]=a[k];
a[k]=t;
}
}
}
for(j=0;j<A;j++)//查询是否越界
if(a[j]>c)
break;
if(j<A)//越界处理,A值变小
A=j;
for(l=0;l<A;l++){
for(j=c;j>=a[l]+l;j--){//插入列
for(k=1;k<=r;k++){
cell[k][j+1].r=cell[k][j].r;
cell[k][j+1].c=cell[k][j].c;
}
}
for(k=1;k<=r;k++){
cell[k][a[l]+l].r=0;
cell[k][a[l]+l].c=0;
}
c+=1;
}
}else if(strcmp(cmd,"EX")==0){
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
tmpcell=cell[r1][c1];
cell[r1][c1]=cell[r2][c2];
cell[r2][c2]=tmpcell;
}
}
kase++;
if(kase>1)
printf("\n");
printf("Spreadsheet #%d\n",kase);
scanf("%d",&n);//查
for(i=0;i<n;i++){
scanf("%d%d",&r1,&c1);
printf("Cell data in (%d,%d) ",r1,c1);
for(j=1;j<=r;j++){
for(k=1;k<=c;k++){
if(cell[j][k].r==r1&&cell[j][k].c==c1){
printf("moved to (%d,%d)\n",j,k);
break;
}
}
if(k<=c)//查询到,退出
break;
}
if(j==r+1)//未查询到
printf("GONE\n");
}
}
return 0;
}