个人学习记录,代码难免不尽人意。
呃,今天做了做19年的复试上机题,死在hash表上了,后面详细解释。心态要好,心态要好
7-1 Conway’s Conjecture
John Horton Conway, a British mathematician active in recreational mathematics, proposed a conjecture in 2014: arrange the factors of any given number in ascending order, and pull the exponents down, we can get another number. Keep doing so we must end up at a prime number. For example:
18=2×32
232=23×29
2329=17×137
17137 is a prime.
Now you are supposed to write a program to make one step verification of this conjecture. That is, for any given positive integer N, you must factorize it, and then test if the number obtained from its factors is a prime.
By the way, this conjecture has been proven false by James Davis, who has discovered a counter example: 135323853961879=13×53 2 ×3853×96179. Alas …
Input Specification:
Each input file contains one test case which gives a positive integer N (<10 5 ).
Output Specification:
For each case, first print in a line the number obtained from N’s factors. The in the next line, print Yes if the above number is a prime, or No if not.
Sample Input 1:
2329
Sample Output 1:
17137
Yes
Sample Input 2:
124
Sample Output 2:
2231
No
Sample Input 3:
87516
Sample Output 3:
2232111317
No
19分代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<stack>
using namespace std;
bool isprime(long long n){if(n<=1) return false;int mid=(int)sqrt(1.0*n);for(int i=2;i<=mid;i++){if(n%i==0) return false;}return true;
}
const int maxn=10010;
map<int,int> mp;
string tostring(int n){string num;stack<int> s;while(n!=0){int a=n%10;n=n/10;s.push(a);}while(!s.empty()){int a=s.top();s.pop();num+=a+'0';}return num;
}
long long toint(string s){long long num=0;for(int i=0;i<s.size();i++){num=num*10+s[i]-'0';
// cout << num <<endl;}return num;
}
int main(){int n;scanf("%d",&n);int mid=(int)sqrt(1.0*n);for(int i=2;i<=mid;i++){while(n%i==0&&isprime(i)){if(mp.find(i)==mp.end()){mp.insert(make_pair(i,1));}else{mp[i]++;} n/=i;}}if(n!=1){mp.insert(make_pair(n,1));}string num;for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
// cout << it->first <<" "<<it->second << endl;if(it->second==1){string temp=tostring(it->first);num+=temp;}else{num+=tostring(it->first);num+=tostring(it->second);}}long long res;res=toint(num);printf("%lld\n",res);if(isprime(res)){printf("Yes\n");}else printf("No\n");}
挺简单的一道题,我估计是我忘记处理特殊情况了扣了一分,当输入等于1的时候应该直接输出1 NO才对。
7-2 Play with Linked List
Address Data Next
where Address is the position of the node, Data is a positive integer no more than 10
5
, and Next is the position of the next node. It is guaranteed that there are at least two nodes on the list.
Output Specification:
For each case, output in order the resulting linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 68237
68237 6 33218
33218 3 99999
99999 5 12309
12309 2 00100
00100 1 -1
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<stack>
using namespace std;
const int maxn=100010;
struct node{int address;int data;int next;int before;
}Node[maxn];
node temp[maxn];
int main(){int begin,n,k;scanf("%d %d %d",&begin,&n,&k);for(int i=0;i<n;i++){int address,data,next;scanf("%d %d %d",&address,&data,&next);Node[address].address=address;Node[address].data=data;Node[address].next=next;}int op=begin,be=begin;Node[op].before=-1;op=Node[op].next;while(op!=-1){Node[op].before=be;be=op;op=Node[op].next;}op=begin;int index1,index2;int cnt=0;while(op!=-1){cnt++;if(cnt==k){index1=op;}if(Node[op].next==-1){index2=op;}op=Node[op].next;}bool flag=true;cnt=0;int tag=index1;while(index1!=-1&&index2!=tag){if(flag){temp[cnt++]=Node[index1];index1=Node[index1].before;flag=false;}else{temp[cnt++]=Node[index2];index2=Node[index2].before;flag=true;}}while(index1!=-1){temp[cnt++]=Node[index1];index1=Node[index1].before;}while(index2!=tag){temp[cnt++]=Node[index2];index2=Node[index2].before;}for(int i=0;i<cnt;i++){if(i!=cnt-1){printf("%05d %d %05d\n",temp[i].address,temp[i].data,temp[i+1].address);}else{printf("%05d %d -1\n",temp[i].address,temp[i].data);}}
}
比较简单的一道题,我采用了双向链表来做的,找到第k个节点和最后一个节点然后开始从后往前遍历并存储到一个新的静态链表中。
7-3 Unsuccessful Searches
The above figure is a question from GRE-CS 2018. It states:
Given an initially empty hash table HT of size 11. The hash function is H(key)=key%7, with linear probing used to resolve the collisions. Now hash the keys 87, 40, 30, 6, 11, 22, 98 and 20 one by one into HT. What is the average search time for unsuccessful searches?
The answer is 6.
Now you are supposed to write a program to solve this kind of problems.
Input Specification:
Each input file contains one test case. For each case, the first line gives 3 positive integers TSize (≤10
3
, the table size), M (≤TSize, the divisor in the hash function), and N (≤TSize, the number of integers to be inserted). Then N non-negative integers (≤10
4
) are given in the next line, separated by spaces.
Output Specification:
Print in a line the average search time for unsuccessful searches, after hashing the N integers into the table. The answer must be accurate up to 1 decimal place.
Sample Input 1:
11 7 8
87 40 30 6 11 22 98 20
Sample Output 1:
6.0
Sample Input 2:
3 3 3
81 2 5
Sample Output 2:
4.0
Note: In sample 2, the last test of the original position counts as well.
别人的代码,这道题当时我没弄懂
#include <iostream>
#include <vector>
using namespace std;
int main() {int tsize,m,n,num;cin>>tsize>>m>>n;vector<int> rec(tsize,-1);for(int i=0;i<n;i++){cin>>num;for(int j = 0; j < tsize; j++){int pos = (num % m + j) % tsize;if(rec[pos] == -1){rec[pos] = num;break;}} }double sum = 0;//根据哈希函数地址为MODm,因此任何一个数经散列函数计算以后的初始地址只可能在0~m-1的位置for(int i = 0; i < m; i++){for(int j = 0; j <= tsize; j++){sum++; //计算到此位置离空位置的距离//找到空位置 int pos = (i + j) % tsize;if(rec[pos] == -1){break;}}}printf("%.1f", sum/m);return 0;
}
这道题让我没弄懂什么意思,后来我才明白了处理冲突的函数和hash散列函数不是一个函数!
散列函数是第一次用来求pos: x % M , 即题中的 H(Key) = key % 7
而冲突处理函数是针对表长的,可以散列到整张表中,nex = (pos + di) % TSize, 即题中的 nex = (pos + i ) % 11。
然后就是平均查找失败长度的概念了,这个我们需要知道(也是一个坑,之前犯过):查找到hash表为空的时候就可以判断查找失败了!如果一直不为空的话需要额外加一次查找次数,题目中说了。然后平均查找失败长度就是在0~m-1之间(因为hash散列函数只能得到这个范围的结果)处理,每个节点向后查询,直到查找到hash表为空或者Tsize次,然后所有次数除以节点个数就是我们最终想要的答案了。
这道题重点在于知道散列函数和冲突处理函数的模数不一定相同。
7-4 Ambulance Dispatch
Given the map of a city, with all the ambulance dispatch centers (救护车派遣中心) and all the pick-up spots marked. You are supposed to write a program to process the emergency calls. It is assumed that the callers are waiting at some pick-up spot. You must inform the nearest (that is, to take the minimum time to reach the spot) dispatch center if that center has at least one ambulance available. Note: a center without any ambulance must not be considered.
In case your options are not unique, inform the one with the largest number of ambulances available. If there is still a tie, choose the one that can pass the least number of streets to reach the spot, which is guaranteed to be unique.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers N
s
(≤10
3
) and N
a
(≤10), which are the total number of pick-up spots and the number of ambulance dispatch centers, respectively. Hence the pick-up spots are numbered from 1 to N
s
, and the ambulance dispatch centers are numbered from A−1 to A−N
a
.
The next line gives N
a
non-negative integers, where the i-th integer is the number of available ambulances at the i-th center. All the integers are no larger than 100.
In the next line a positive number M (≤10
4
) is given as the number of streets connecting the spots and the centers. Then M lines follow, each describes a street by giving the indices of the spots or centers at the two ends, followed by the time taken to pass this street, which is a positive integer no larger than 100.
Finally the number of emergency calls, K, is given as a positive integer no larger than 10
3
, followed by K indices of pick-up spots.
All the inputs in a line are separated by a space.
Output Specification:
For each of the K calls, first print in a line the path from the center that must send an ambulance to the calling spot. All the nodes must be separated by exactly one space and there must be no extra space at the beginning or the end of the line. Then print the minimum time taken to reach the spot in the next line. It is assumed that the center will send an ambulance after each call. If no ambulance is available, just print All Busy in a line. It is guaranteed that all the spots are connected to all the centers.
Sample Input:
7 3
3 2 2
16
A-1 2 4
A-1 3 2
3 A-2 1
4 A-3 1
A-1 4 3
6 7 1
1 7 3
1 3 3
3 4 1
6 A-3 5
6 5 2
5 7 1
A-2 7 5
A-2 1 1
3 5 1
5 A-3 2
8
6 7 5 4 6 4 3 2
Sample Output:
A-3 5 6
4
A-2 3 5 7
3
A-3 5
2
A-2 3 4
2
A-1 3 5 6
5
A-1 4
3
A-1 3
2
All Busy
20分代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<vector>
using namespace std;
const int maxn=1010;
const int INF=1000000000;
int G[maxn][maxn];
int nums[15];
int d[maxn];
bool visit[maxn];
vector<int> pre[maxn];
int toint(string s){int num=0;for(int i=0;i<s.size();i++){num=num*10+s[i]-'0';}return num;
}
void dijkstra(int begin,int n){for(int i=1;i<=n;i++){pre[i].clear();}fill(d,d+maxn,INF);fill(visit,visit+maxn,false);d[begin]=0;for(int i=0;i<n;i++){int u=-1,min=INF;for(int j=1;j<=n;j++){if(!visit[j]&&d[j]<min){u=j;min=d[j];}}if(u==-1) return;visit[u]=true;for(int j=1;j<=n;j++){if(!visit[j]&&G[u][j]!=INF){if(d[j]>G[u][j]+d[u]){d[j]=G[u][j]+d[u];pre[j].clear();pre[j].push_back(u);}}}}
}
vector<int> path,temp;
int streets=0;
void dfs(int st,int ed){if(ed==st){temp.push_back(ed);if(path.empty()){path=temp;streets=temp.size();}else{int street=temp.size();if(streets>street){path=temp;streets=street;}}temp.pop_back();return;}temp.push_back(ed);for(int i=0;i<pre[ed].size();i++){dfs(st,pre[ed][i]);}temp.pop_back();
}
int main(){for(int i=0;i<maxn;i++){for(int j=0;j<maxn;j++){G[i][j]=INF;}}int n,m;scanf("%d %d",&n,&m);for(int i=1;i<=m;i++){scanf("%d",&nums[i]);}int k;scanf("%d",&k);for(int i=0;i<k;i++){string a,b;int a1,b1,dis;cin >> a >> b>> dis;if(a[0]=='A'){a1=toint(a.substr(2,a.size()-2))+n;b1=toint(b);}else if(b[0]=='A'){b1=toint(b.substr(2,b.size()-2))+n;a1=toint(a);}else{a1=toint(a);b1=toint(b); }G[a1][b1]=dis;G[b1][a1]=dis;}scanf("%d",&k);for(int p=0;p<k;p++){int ed;scanf("%d",&ed);dijkstra(ed,n+m);int end=-1;int min=INF;int street=0;for(int j=n+1;j<=n+m;j++){if(nums[j-n]>0){if(d[j]<min){end=j;min=d[j];}else if(d[j]==min){if(nums[end-n]<nums[j-n]){end=j;}else if(nums[end-n]==nums[j-n]){path.clear();temp.clear();streets=0;dfs(ed,end);street=streets;path.clear();temp.clear();streets=0;dfs(ed,j);if(street>streets){end=j;street=streets;}}}}}if(end==-1){printf("All Busy\n");continue;}path.clear();temp.clear();streets=0;dfs(ed,end);nums[end-n]--;int time=0;for(int i=0;i<path.size()-1;i++){time+=G[path[i]][path[i+1]];}for(int i=0;i<path.size();i++){if(path[i]>n){printf("A-%d",path[i]-n);}else printf("%d",path[i]);if(i!=path.size()-1) printf(" ");else printf("\n"); }printf("%d\n",time);}}
小时候最害怕的一题,有两个测试点段错误,检查不出问题来了。
后来想想这道题可以用floyd来做,比每次都调用dijkstra逻辑上要清晰许多。