今天郑州下雪了,很大,09年的第一场雪。问了问,家里也下雪了,也很大。今年的雪来的可真早。
这两天在看第五次的编程比赛题:http://www.programfan.com/club/showpost.asp?id=122355&t=o
这次的冠军是wgkujgg,他用的是哈希表,但我还没学到哈希表,所以我仔细分析了eastcowboy的方法,eastcowboy的算法设计的真的很巧妙,他用的是二叉树,这是他的代码及我给的注释:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
/*#include<assert.h>*/
typedef struct node
{ char name[31];
int score;
struct node *left,*right;
}NODE;
NODE *root = NULL;
int nStudent,nCourse,rank,nowscore;
void MakeTree()
{ int i,cmp;
char buf[31];
NODE *p,*parent; /*parent相当于一个中介节点*/
scanf("%d",&nStudent); /*学生总数*/
getchar();
/*单独处理第一个*/
gets(buf);
root = malloc(sizeof(NODE)); /*root是根节点*/
strcpy(root->name,buf);
root->score = 0; /*在函数MakeTree中分数都先置为0*/
root->left = root->right = NULL; /*左右孩子置空*/
/*循环处理后续结点*/
for(i=1;i<nStudent;++i)
{ gets(buf);
p = root;
while( p )
{ parent = p; /*p节点此时的地址要放到parent中保存*/
cmp = strcmp(buf,p->name);
/*assert(cmp != 0);*/
if(cmp>0)
p = p->right; /*名字比原先输入的大的放到右孩子*/
else /*否则左孩子*/
p = p->left; 虽然你输入名字时没有在意大小之分,但程序仍对它们排序了,这样查找liming的名字时容易
}
p = malloc(sizeof(NODE));
strcpy(p->name,buf);
p->score = 0; /*在函数MakeTree中分数都先置为0的*/
p->left = p->right = NULL; /*左右孩子置空*/
/*cmp = strcmp(p->name,parent->name);*/
if(cmp>0)
{ parent->right = p; /*parent就是这样的作用,它保存p节点上一次的地址*/
}
else
{ parent->left = p;
}
} for循环结束
scanf("%d",&nCourse); /*这一步输入考试次数*/
} /*上面只输入名字,分数都置0*/
int *searchscore(char *name) /*此函数的作用是找到名字所对应分数的地址*/
{ NODE *p;
int cmp;
p = root;
while(p)
{ cmp = strcmp(name,p->name);
if(cmp>0)
p = p->right;
else if(cmp<0)
p = p->left;
else
return &(p->score); /*找到名字后返回的他分数的地址*/
}
/*assert(1);*/
return NULL;
}
void PostOrder(NODE *p) /*此函数搜索的是liming的名次*/
{ if(p->left)
PostOrder(p->left);
if(p->right)
PostOrder(p->right);
if(p->score > nowscore)
++rank;
}
int main()
{ int i,j,temp;
int *pscore;
char namebuf[31],c;
MakeTree();
pscore = searchscore("Li Ming");
for(i=0;i<nCourse;++i) /*nCcourse是考试次数*/
{ for(j=0;j<nStudent;++j)
{ scanf("%d",&temp); /*temp是成绩*/
getchar();
gets(namebuf); /*输入名字,后面一行searchscore(namebuf)返回该名字的分数的地址*/
*(searchscore(namebuf)) += temp;
}
/*先输入所有名字然后输入分数和名字,名字不再放到树中,分数找到名字对应的分数的地址并放入*/
rank = 1;
nowscore = *pscore;
PostOrder(root); /*调用Post0rder函数找到liming的名次*/
printf("%d\n",rank);
}
return 0;
}
这是eastcowboy的方法。而我用的方法就太笨太原始了,一下子定义了50个10000个字节的数组,其实这个题之所以给10000、50这么大的数字就是要你设计出一种高效率的算法,用多少空间分配多少空间,准确来说我的程序是失败的!这是我的代码:
#include <stdio.h>
#include <string.h>
struct node
{ int number;
char name[30];
}a[50][10000];
main()
{ int temp1,n,i,j,m,k;
char ch='#';
printf("please input the students totals:\n");
scanf("%d",&n); /*学生总数*/
printf("please input the names:\n");
for(i=0;i<n;i++)
scanf("%s",a[0][i].name);
printf("please input the exam times:\n");
scanf("%d",&m); /*考试次数*/
for(i=0;i<m;i++)
{ printf("please input the %dth student score and name:\n",i+1);
for(j=0;j<n;j++)
scanf("%d%s",&a[i][j].number,a[i][j].name);
}
while(ch!='q')
{
printf("please input the time you want to see:\n");
scanf("%d",&k);
k--; /*因为数组中行的下标从0开始,所以你所查找的行比实际行少1*/
for(j=0;j<n-1;j++) /*用选择法排序*/
{ temp1=j;
for(i=j+1;i<n;i++)
if(a[k][i].number<a[k][temp1].number)
temp1=i;
a[49][9]=a[k][j];
a[k][j]=a[k][temp1];
a[k][temp1]=a[49][9];
}
printf("The score from small to big is:\n");
for(i=0;i<n;i++)
{ printf("%d %s||",a[k][i].number,a[k][i].name);
if(strcmp(a[k][i].name,"liming")==0)
m=a[k][i].number; /*此处使用m*/
}
for(i=0;i<n;i++)
if(a[k][i].number==m) j=i; /*j已没有用处,此处使用j*/
printf("the mingci is %d \n",n-j);
ch=getchar();
}
getchar();
return 0;
}