您的位置:首页 > 其它

小白书练习题5.5.3 排序检索类、

2016-05-14 21:26 288 查看
UVA 340 Master-Mind Hints

题意:猜数字游戏,给n个数的序列给你、接下来一行是答案序列、剩下的都是猜测序列、对于每一个猜测序列,统计有多少个数字相同并且位置相同、有多少数字相同位置不同、每一个数字只能用一次、

思路:直接统计可以求出数字相同并且位置相同的哪一些数、在此过程中我加了一个标记数组、标记那些用过的数的位置为1,没用过为0;然后枚举猜测中哪些没用过的数字、去答案序列中找、当数字相等并且答案行中那个数也没用过时、计数加1;

#include<cstdio>
#include<cstring>
const int qq=1005;
int num[qq];
int digit[qq][qq];
int vis[qq][qq];
int comp[qq];
int main()
{
int n;
int t=1;
while(~scanf("%d",&n)){
memset(vis,0,sizeof(vis));
if(n==0)    break;
for(int i=1;i<=n;++i)
scanf("%d",&num[i]);
int k=1;
while(1){
int ans=0;
for(int i=1;i<=n;++i){
scanf("%d",&digit[k][i]);
if(digit[k][i]==0)    ans++;
}
if(ans==n)    break;
k++;
}
printf("Game %d:\n",t++);
for(int l,j,i=1;i<k;++i){
int a,b;a=b=0;
memset(comp,0,sizeof(comp));        //每个数确切的只能用一次、
for(j=1;j<=n;++j)    //因为开始就可以把位置相同的数给处理掉、所以到下面循环的时候就不用判断位置相同与否了、
if(num[j]==digit[i][j])    ++a,vis[i][j]=comp[j]=1;    //位置相同a++
for(j=1;j<=n;++j)    //数字相同、位置不同b++;
if(!vis[i][j])    for(l=1;l<=n;++l)    if(!comp[l]&&digit[i][j]==num[l]){comp[l]=vis[i][j]=1;b++;break;}
printf("    (%d,%d)\n",a,b);
}
}
}


UVA 10420 List of Conquests

题意:就是统计每个国家有多少个人、对于每个国家按字典序输出

思路:map容器直接统计,不会出现重名、

#include<map>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
int main()
{
int n;cin >> n;
map<string,int>Q;
string str;
string coun;
for(int i=0;i<n;++i){
cin >> coun;
if(!Q[coun])
Q[coun]=1;
else
Q[coun]++;
getline(cin,str);
}
map<string,int>::iterator it;
for(it=Q.begin();it!=Q.end();++it)    //记得it是指针迭代器、
cout << it->first << " " << it->second << endl;
return 0;
}


UVA 10474 Where is the Marble?

题意:给你n个数字的序列、然后又m次询问、每一次m给出一个数字a,在所给的序列中找出<=a的第一个位置

思路:题目开始给的序列是散乱的、要进行排序、这里用了lower_bound函数、返回<=键值的第一个地址

#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int qq=10005;
int num[qq];
int vis[qq];
int quicksort(int l,int r)
{
int x=num[l];
int i,j;
i=l;j=r;
while(i<j){
while(i<j && num[j]>=x)    --j;
num[i]=num[j];
while(i<j && num[i]<=x)    ++i;
num[j]=num[i];
}
num[i]=x;
return i;
}
void quick(int l,int r)
{
if(l<r){
int temp=quicksort(l,r);
quick(l,temp-1);
quick(temp+1,r);
}
}
int main()
{
int n,m;
int k=1;
while(~scanf("%d%d",&n,&m)&&(n&&m)){
memset(vis,0,sizeof(vis));
for(int i=0;i<n;++i){
scanf("%d",&num[i]);
vis[num[i]]=1;
}
quick(0,n-1);
printf("CASE# %d:\n",k++);    //没加冒号贡献两发、
for(int i=0;i<m;++i){
int ans;scanf("%d",&ans);
if(!vis[ans])    printf("%d not found\n",ans);
else    printf("%d found at %d\n",ans,lower_bound(num,num+n,ans)-num+1);
}
}            //记得科普一下lower_bound函数、
return 0;
}


UVA 152 Tree's a Crowd

题意:给出一系列的点、给对每个点找出距离该点最近的点、然后统计距离在什么范围里面、

思路:按题意来就行了、

#include<cmath>
#include<cstdio>
#include<cstring>
int num[15];
double f(double x,double y,double z,double a,double b,double c)
{
return sqrt(pow(x-a,2.0)+pow(y-b,2.0)+pow(z-c,2.0));
}
struct Point
{
double x,y,z;
}point[5050];
int main()
{
double a,b,c;
memset(num,0,sizeof(num));
int k=0;
while(scanf("%lf%lf%lf",&a,&b,&c)!=EOF){
if(a==0&&b==0&&c==0)    break;
point[k].x=a;point[k].y=b;point[k].z=c;
k++;
//printf("%lf\n",ans);
}
//    for(int i=0;i<k;++i)
//        printf("%lf %lf %lf\n",point[i].x,point[i].y,point[i].z);
double ans,minx;
for(int j,i=0;i<k;++i){    //找寻离i点最近的一个点、
minx=1e6;
for(j=0;j<k;++j)
if(i!=j){
ans=f(point[i].x,point[i].y,point[i].z,point[j].x,point[j].y,point[j].z);
if(ans<minx)    minx=ans;
}
if(minx<1.0)    num[1]++;        //然后比较距离、
else if(minx<2.0)    num[2]++;
else if(minx<3.0)    num[3]++;
else if(minx<4.0)    num[4]++;
else if(minx<5.0)    num[5]++;
else if(minx<6.0)    num[6]++;
else if(minx<7.0)    num[7]++;
else if(minx<8.0)    num[8]++;
else if(minx<9.0)    num[9]++;
else if(minx<10.0)    num[10]++;
}
for(int i=1;i<=10;++i)
printf("%4d",num[i]);        //格式控制输出4个单位间隔、
printf("\n");
return 0;
}    //题意确实......我太蒻了、


UVA 299 Train Swapping

题意:在所给n个数的序列中,要将这个序列从小到大排列需要多少次交换?只有相邻两个值之间才可以交换、

思路:- - 、就是冒泡排序的思想、 记录交换的次数就行了、

#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int num[105];
int main()
{
int t;cin >> t;
while(t--){
int n;cin >> n;
for(int i=0;i<n;++i)
cin >> num[i];
int k=0;
for(int j,i=0;i<n;++i)
for(j=0;j<n-i-1;++j)
if(num[j]>num[j+1]){
++k;
int t=num[j];
num[j]=num[j+1];
num[j+1]=t;
}
cout << "Optimal train swapping takes " << k << " swaps." << endl;
}
return 0;
}


UVA 120 Stacks of Flapjacks

题意:翻煎饼、举个例子把、样例 5 1 2 3 4、注意最右边是底部、 如果此时进行filp(1)那么从1到最右边这连续的序列都反转过来、 也就变成了 4 3 2 1 5、联想一下现实生活中的翻转那种煎饼就能懂了、

思路:题目要求大的数在底部、也就是最右边、 但是我为了记录filp(x)中的x方便、我把最左边当成底部了、对于栈这种数据结构、底部的东西要出来只能将前面的东西一个一个取出来才能达到目的、那么此题也就是说每一次操作的时候先让当前乱序序列中的最大数放进底部、 那么此时对于当前最大数只有三种情况、第一种是刚好在对应的底部、第二种是刚好在栈顶、第三种是在栈顶和对应底部的中间、至于为什么自己去思考把、然后分别对这三种情况进行排查和对应的操作就行了、

#include<cmath>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
string s;
int num[105];
int tar[105];
int id[105];
int cmp(int a,int b)
{
return a>b;
}
int f(int a,int b)
{
while(a<b){
swap(num[a],num[b]);
a++;b--;
}
}
int main()
{
while(getline(cin,s)){
int flag=0;
int k=1;
int ans=0;
s[s.size()]='a';
for(int i=0;i<=s.size();++i)
if(s[i]>='0'&&s[i]<='9'){
ans=ans*10+s[i]-'0';
flag=1;
}
else{
if(flag==1)    num[k++]=ans;
ans=0;
flag=0;
}
k=k-1;
for(int i=1;i<=k;++i)
tar[i]=num[i];
for(int i=1;i<=k;++i)    //输出原来的序列、
if(i==1)    printf("%d",num[i]);
else        printf(" %d",num[i]);
printf("\n");
for(int i=1;i<=(k+1)/2;++i)    //为了方便记录翻饼的位置、我把最左边当成底部、
swap(num[i],num[k-i+1]);
sort(tar+1,tar+1+k,cmp);    //这里排序也是从大到小排列、因为你最后要得到这个序列、
int c=0;
for(int i=1;i<=k;++i){
ans=tar[i];
for(int j=1;j<=k;++j)
if(num[j]==ans){
if(j==i)    break;// 第一种情况乱序序列的当前最大值的位置等于对应的底部位置
else if(j==k){    //第二种情况位于栈顶、
id[c++]=i;
f(i,k);
}
else{    //第三种情况位于中间、
id[c++]=j;
f(j,k);
id[c++]=i;
f(i,k);
}
break;
}
}
for(int i=0;i<c;++i)    //输出格式要控制好、
if(i==0)    printf("%d",id[i]);
else        printf(" %d",id[i]);
if(c!=0)    printf(" 0\n");
else        printf("0\n");
}
return 0;
}


UVA 156 Ananagrams

题意:统计所有单词经过重排后只存在一个、 那么输出原单词、比较过程不区分大小写 但输出的时候是给定单词列表中的单词,并且按字典序列输出、

思路:我用结构体存了原单词和经过小写处理的重排后的单词、然后枚举每一个单词寻找是否有相同的、

#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int qq=105;
struct Word        //用结构体存原单词和经过重排之后的单词、
{
char ori[qq];
char rear[qq];
}word[qq*10];
char s[qq*10];
int main()
{
int tot=0;
while(gets(s)){
if(s[0]=='#')    break;
char w[qq];
int k=0;
int flag=0;
int len=strlen(s);
s[len]='.';
for(int i=0;i<=len;++i)
if(s[i]>='A'&&s[i]<='z'){
w[k++]=s[i];
flag=1;
}
else{
if(flag){
w[k]='\0';
strcpy(word[tot++].ori,w);
}
flag=0;
k=0;
}
}
for(int i=0;i<tot;++i){
int len=strlen(word[i].ori);
for(int j=0;j<len;++j)
word[i].rear[j]=tolower(word[i].ori[j]);//因为比较的时候不区分大小写、所以一律小写
sort(word[i].rear,word[i].rear+len);
}
int vis[qq*10];
memset(vis,0,sizeof(vis));
for(int i=0;i<tot;++i)
for(int j=1;j<tot;++j)
if(strcmp(word[j].ori,word[j-1].ori)<0)    swap(word[j-1],word[j]);//i,j代表什么要清晰、
for(int j,i=0;i<tot;++i)
if(!vis[i])
for(j=i+1;j<tot;++j)
if(strcmp(word[i].rear,word[j].rear)==0)    vis[i]=vis[j]=1;
for(int i=0;i<tot;++i)
if(!vis[i])    printf("%s\n",word[i].ori);
return 0;
}     // lexicographic (case-sensitive) order.  字典序输出、


UVA 400 Unix ls

题意:制作一个列表、给出n个文件名、每一行尽量最多值容纳60个字符(可能有文件名字符长度超过60),让后要你输出一个列表、列表中每一列按字典序顺序来排,要求尽可能少的行、 每个单位长度是当前文件名的最大长度+2,还要求进行左对齐、

思路:可以求出当前的最大列、当列最大时行自然是最小的了、 那么此题还有一个坑点我WA了一发、 就是如过出现最长单词长度超过60、那么在这一行内输出所有文件名

#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
struct List
{
char name[105];
bool operator < (List a)
{
return strcmp(name,a.name)<strcmp(a.name,name);
}
}list[105];
int vis[105];
int main()
{
int flag=1;
int t=1;
while(~scanf("%d",&n)){    //题目要求尽可能少的行、那么就要尽可能多的列、
getchar();
int maxn=0;
for(int i=0;i<n;++i){
scanf("%s",&list[i].name);
int len=strlen(list[i].name);
maxn=maxn>len?maxn:len;
}
if(flag){
for(int i=0;i<60;++i)    printf("-");
printf("\n");
flag=0;
}
memset(vis,0,sizeof(vis));
sort(list,list+n);
int row,col;
col=60/(maxn+2);
if(col==0)    col=1;    //超过60要特别处理、总不能什么都不输出吧、
row=ceil(n*1.0/col);
//printf("%d %d\n",row,col);
int k=0;
if(t!=1){
for(int i=0;i<60;++i)    printf("-");
printf("\n");
}
t++;
while(1){
int p=0;
int count=0;
for(int i=k;i<n;i+=row)
if(count==col)    break;
else if(!vis[i]){
count++;
p=1;
vis[i]=1;
printf("%-*s",maxn+2,list[i].name);    //-号表示左对齐、
}                                    //*号是格式控制符可以被变量maxn+2代替、
if(p==0)    break;
printf("\n");
k++;
}
}
return 0;
}
//There will be as many columns as will fit in 60 characters
//表示尽可能多的列将适合60个字符以内、这句话就表明了会有超过60的、
//所以当最长文件名不小于60的时候col就要为1了、


UVA 123 Searching Quickly

题意:给一些单词、在下列句子中这个单词要被忽略、其他所有单词都是关键词、对于每一个关键词、输出一该关键词所在的句子、其他所有都小写、只有关键词大写、输出按关键词的字典序来、对于同一个关键词出现在不同句子中、先输出最早出现的那一个、对于在同一句的关键词、先输出最左边的、关键词不区分大小写

思路:题目不难、就是处理起来很麻烦、

#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<ctype.h>
using namespace std;
char ignore[205][15];
char word[205][205];
struct Word
{
char word[205];    // 句子、
char tar[105];    //关键词、
int s,e;        //关键词在句子中的起始位置、
int titleid;    //句子顺序、
int index;        //这个存的是每个关键词出现在句子中首字母的位置、
bool operator < (Word a)const
{
if(strcmp(tar,a.tar)==0){
if(titleid==a.titleid)    return index<a.index;
return titleid<a.titleid;
}
return strcmp(tar,a.tar)<strcmp(a.tar,tar);
}
}Q[10005];
int main()
{
int k1=0,k2=0;
while(1){
gets(ignore[k1]);
for(int i=0;i<strlen(ignore[k1]);++i)
ignore[k1][i]=tolower(ignore[k1][i]);
if(ignore[k1][0]==':')    break;
k1++;
}
while(gets(word[k2])){
for(int i=0;i<strlen(word[k2]);++i)
word[k2][i]=tolower(word[k2][i]);    //全部转化为小写、因为输出的时候只有关键词要大写、
k2++;
}
//    printf("%d %d\n",k1,k2);
int k=0;
int top=0;
int start;
char s[55];
for(int i=0;i<k2;++i){
int flag=0;
for(int j=0;j<=strlen(word[i]);++j){
if(islower(word[i][j])){    //一个一个单词取出来、
if(flag==0){
start=j;        //记录单词的首字母位置、
flag=1;
}
s[k++]=word[i][j];
}
else{
s[k]='\0';
int l;
for(l=0;l<k1;++l)    //看提取出来的单词是不是要被忽略的单词、
if(strcmp(ignore[l],s)==0)    break;
if(l==k1){
strcpy(Q[top].word,word[i]);
strcpy(Q[top].tar,s);        //存取关键词、
Q[top].s=start;
Q[top].e=start+k-1;
Q[top].titleid=i;
Q[top].index=start;
top++;
}
k=0;
flag=0;
}
}
}
sort(Q,Q+top);
for(int i=0;i<top;++i){
for(int j=0;j<strlen(Q[i].word);++j)
if(j>=Q[i].s&&j<=Q[i].e)    printf("%c",toupper(Q[i].word[j]));
else                        printf("%c",Q[i].word[j]);
printf("\n");
}

return 0;
}


UVA 10194 Football (aka Soccer)

题意:统计题目中给定的信息、按要求的顺序排序就没啥问题、

思路:没啥思路把、都是直接模拟的问题、就是细节处理不同而已、

#include<cmath>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<ctype.h>
using namespace std;
string str;
struct Team
{
string name;    //队名、
int total;    //总得分
int time;    //比赛场次、
int win;    //赢、
int tie;    //平局、
int loss;    //输、
int score;    //每一场自己的goal、
int against;    //每一场别人的goal、
int play;
}team[40];
int cmp(Team a,Team b)    // 排序要求、
{
if(a.total!=b.total)    return a.total>b.total;
if(a.win!=b.win)    return a.win>b.win;
if(a.score-a.against!=b.score-b.against)    return a.score-a.against>b.score-b.against;
if(a.score!=b.score)    return a.score>b.score;
if(a.play!=b.play)    return a.play<b.play;
string s1,s2;         // 注意最后要求比较的字母序列不区分大小写、
for(int i=0;i<a.name.size();++i)
s1+=tolower(a.name[i]);
for(int i=0;i<b.name.size();++i)
s2+=tolower(b.name[i]);
return s1<s2;
}
int main()
{
int t;cin >> t;
cin.get();
while(t--){
getline(cin,str);
int n;cin >> n;cin.get();
for(int i=0;i<n;++i){
getline(cin,team[i].name);
team[i].play=team[i].against=team[i].loss=team[i].score=team[i].tie=team[i].time=team[i].total=team[i].win=0;
}
int m;cin >> m;
cin.get();
while(m--){
string temp;
getline(cin,temp);
string team1,team2;
int goal1,goal2;goal1=goal2=0;
int len=temp.size();
int i;                //下面有c的scanf格式控制来运算取值貌似也挺方便、
for(i=0;i<len&&temp[i]!='#';++i)    //(%s#%d@%d#%s)
team1+=temp[i];                        // 我这里是一个一个把信息提取出来、
for(i=i+1;i<len&&temp[i]!='@';++i)
goal1=goal1*10+temp[i]-'0';
for(i=i+1;i<len&&temp[i]!='#';++i)
goal2=goal2*10+temp[i]-'0';
for(i=i+1;i<len&&temp[i]!='#';++i)
team2+=temp[i];
int id1,id2;
for(int j=0;j<n;++j)         //根据自己定义的结构体来处理、
if(team[j].name==team1)    id1=j;
else if(team[j].name==team2)    id2=j;
team[id1].time++;team[id2].time++;
team[id1].score+=goal1;team[id1].against+=goal2;
team[id2].score+=goal2;team[id2].against+=goal1;
team[id1].play++;team[id2].play++;
if(goal1>goal2){
team[id1].win+=1;team[id1].total+=3;
team[id2].loss+=1;
}
else if(goal2>goal1){
team[id2].win+=1;team[id2].total+=3;
team[id1].loss+=1;
}
else{
team[id1].tie++;team[id2].tie++;
team[id1].total+=1;team[id2].total+=1;
}
}
cout << str << endl;
sort(team,team+n,cmp);
for(int i=0;i<n;++i)
cout << i+1 << ") " << team[i].name << " " << team[i].total << "p, " << team[i].play << "g ("
<<  team[i].win << "-" << team[i].tie << "-" << team[i].loss << "), "
<< team[i].score-team[i].against << "gd (" << team[i].score << "-"
<< team[i].against << ")" << endl;
if(t)    printf("\n");    // 没加WA一发、
}
return 0;
}


UVA 755 487--3279

题意:给一些字母对应数字的表给你、并且给定电话号码的格式xxx-xxxx、要你求出那些出现次数超过两次的电话号码、并且输出按电话号码的字典序来、

思路:map容器直接开搞、

#include<cmath>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<ctype.h>
#include<map>
using namespace std;
const int qq=100005;//数组开小了、RE
const int aa=105;
char di[40]={"22233344455566677778889990"};
string tel[qq];
int main()
{
int t;scanf("%d",&t);
getchar();
while(t--){
int n;scanf("%d",&n);
for(int i=1;i<=n;++i)
cin >> tel[i];
map<string,int>Q;
for(int i=1;i<=n;++i){
int len=tel[i].size();
string ss;
for(int j=0;j<len;++j)
if(tel[i][j]>='0'&&tel[i][j]<='9')    ss+=tel[i][j];
else if(isalpha(tel[i][j]))    ss+=di[tel[i][j]-'A'];
ss.insert(3,"-");    //这个函数可以在位置3的地方插入字符串"-";
Q[ss]++;
}
map<string,int>::iterator it;
int flag=1;
for(it=Q.begin();it!=Q.end();++it)
if(it->second>1){
cout << it->first << " " << it->second << endl;
flag=0;
}
if(flag==1)    printf("No duplicates.\n");    //判断又判反了、WA
if(t)    printf("\n");
}
return 0;
}


UVA 10785 The Mad Numerologist

题意:首先给出一个表代表着每个字母对应的值value、然后说每一个元音(vowel)字母AEIOU可以使用21次、每一个辅音(consonant)可以使用5次、现在给你一个n值要你构造奇数为为元音偶数为为辅音的最小值序列、

思路:还是那题意来模拟、

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
char vm[]={"AUEOI"};
char cm[]={"JSBKTCLDMVNWFXGPYHQZR"};
char ans[300],cns[300];
int main()
{
int t;scanf("%d",&t);
int k=1;
while(t--){
int n;scanf("%d",&n);
int end=(n+1)/2;
for(int i=0;i<end;++i){
ans[i]=vm[i/21];    //统计元音、
cns[i]=cm[i/5];        //统计辅音、
}
sort(ans,ans+(n+1)/2);    //排序、
sort(cns,cns+(n+0)/2);
printf("Case %d: ",k++);
for(int i=0;i<n;++i)
printf("%c",i%2?cns[i/2]:ans[i/2]);
printf("\n");
}
return 0;
}


终于把这个章节的题目给做完了、

又来总结一下经验教训吧、

首先呢、题目都不难、但就是处理起来麻烦那么一丢丢、

看题很重要、不能漏信息、尤其在input和output中会给出一定量的信息和要求、

在一个就是格式、在准备交程序之前还检查一下自己的格式是否正确、

另外对一些空白字符的考虑要妥当、

大体就以上这些、

这里面一共是12道题、上周做了4道、本周这里有8道、
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: