PTA 逆散列问题 (30 分)(贪心)
题目链接:https://pintia.cn/problem-sets/1107178288721649664/problems/1107178432099737614
题目大意:
给定长度为 N 的散列表,处理整数最常用的散列映射是 (。如果我们决定用线性探测解决冲突问题,则给定一个顺序输入的整数序列后,我们可以很容易得到这些整数在散列表中的分布。例如我们将 1、2、3 顺序插入长度为 3 的散列表HT[]
后,将得到HT[0]=3
,HT[1]=1
,HT[2]=2
的结果。
但是现在要求解决的是“逆散列问题”,即给定整数在散列表中的分布,问这些整数是按什么顺序插入的?
我的理解:对于当前的数,先看他%n是多少,如果这个位上没有数,那么就把这个数放在这个位置,如果已经存在,就从当前的这个数的位置往后找,直到有空缺的时候停(如果到了最后一个还没有找到,那么再从第一个位置开始找)。
具体思路:首先对数组排一下序,因为我们要求的是字典序最小,那么我们先看第一个数是不是合法的,如果合法,就直接输出。否则,再去找第二小的数,以此类推。
然后再加两个标记数组,标记当前的数是不是用过了,以及当前的位置是否有数存在就可以了。
感谢剑锋学长和张明学长的帮忙┗( ▔, ▔ )┛
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 const int maxn = 2e5+100; 5 int a[maxn],b[maxn]; 6 int ans[maxn]; 7 int pos[maxn],vis[maxn]; 8 int viss[maxn]; 9 int main() 10 { 11 int n; 12 scanf("%d",&n); 13 int tot=0; 14 for(int i=0; i<n; i++) 15 { 16 scanf("%d",&a[i]); 17 if(a[i]>=0){ 18 b[tot++]=a[i]; 19 } 20 } 21 int tmp=0,flag; 22 sort(b,b+tot); 23 for(int i=0; i<tot; i++){ 24 for(int j=0; j<tot; j++){ 25 if(vis[j])//当前的数已经用过了,就不需要再找了 26 continue; 27 flag=1; 28 for(int k=b[j]%n;;){ 29 if(viss[k]==0&&b[j]==a[k]){ 30 vis[j]=1; 31 viss[k]=1; 32 ans[i]=b[j]; 33 flag=0; 34 break; 35 } 36 if(viss[k]==0){ 37 break; 38 } 39 k++; 40 if(k==n) 41 k=0; 42 } 43 if(!flag) 44 break; 45 } 46 } 47 for(int i=0; i<tot; i++){ 48 if(i==0) 49 printf("%d",ans[i]); 50 else 51 printf(" %d",ans[i]); 52 } 53 printf("\n"); 54 return 0; 55 }