题目大意:
给一个整数n,然后是长度为n*(n+1)/2的字符串(仅由26个小写字母组成),这个字符串按三角矩阵依次排列(第一行有1个字母,第二行是3个……第n行有2*n-1个字母),然后判断在这个三角形中,是否存在等边的三角行,它的顶点上的字母都相同,如果存在,输出这个字母,否则输出“LOOOOOOOOSER!”。
模拟,很繁琐的模拟。
存坐标的时候,有点技巧,就是第 i 行的点的纵坐标是其横坐标 i 的 sqrt(3)/3 的整倍数,这样存点的好处是,可以直接用坐标计算两点间的距离,从而判断三角形是否等边。
存完坐标后,在所有出现次数大于等于3次的字母中遍历字符串,枚举每一种情况,就可以了。
这里需要考虑精度问题,还有就是字母输出字母的时候应该按照升序输出,并不是按照它们最先出现的顺序来的,这点困扰了我很久,TAT……
#include<stdio.h> #include<string.h> #include<math.h> #define gi sqrt(3)/3.0 #define Ni 100 #define esp 0.000000001 struct node { double x,y; }p[Ni]; char str[Ni]; int n,min,max,v[Ni]; double dis(int i,int j) { return pow(p[i].x-p[j].x,2) + pow(p[i].y-p[j].y,2); } int fun(int i,int j,int k) { double x=dis(i,j),y=dis(i,k),z=dis(j,k); if(fabs(x-y)<esp && fabs(y-z)<esp && x>0 && y>0 && z>0) return 1; else return 0; } int main() { int n,i,j,k,q,put[Ni],find,flag; while(scanf("%d",&n),n) { getchar(); memset(str,0,sizeof(str)); gets(str); memset(v,0,sizeof(v)); min=30,max=-1; for(i=0;str[i];i++) //统计出现次数,出现的最大,最小字符 { int x=str[i]-'a'; v[x]++; if(str[i]-'a'>max) max=str[i]-'a'; if(str[i]-'a'<min) min=str[i]-'a'; } memset(p,0,sizeof(p)); for(k=0,i=0;i<n;i++) { for(j=0;j<=i;j++) { if(j==0) p[k].x=-i*gi; else p[k].x=p[k-1].x+2*gi; p[k].y=-1.0*i; k++; } } memset(put,0,sizeof(put)); //printf("%d %d/n",min,max); for(i=min;i<=max;i++) { if(!put[i] && v[i]>2) { flag=0; for(j=0;str[j];j++) { if(str[j]!='a'+i)continue; for(k=0;str[k];k++) { if(str[k]!='a'+i)continue; for(q=0;str[q];q++) { if(j!=k && k!=q && j!=q) if(str[j]=='a'+i && str[k]=='a'+i && str[q]=='a'+i && fun(j,k,q)) { put[i]=1,flag=1; break; } } if(flag)break; } if(flag)break; } } } find=0; for(i=min;i<=max;i++) if(put[i])printf("%c",'a'+i),find=1; if(!find)printf("LOOOOOOOOSER!"); puts(""); } return 0; }