题目
Sample Input:
11
33 1 13 12 34 38 27 22 32 -1 21
Sample Output:
1 13 12 21 33 34 38 27 22 32
基本思路
可以使用拓扑排序来解这道题。基本思路如下:将输入保存在散列表后,遍历每个元素,如果元素刚好在它对应余数的位置上,则入度为0,可直接输出;否则,从余数位置出发,用线性探测法到达该位置,对于经过的所有的非空元素位置,生成一条到该元素位置的边,并将该位置入度加1;拓扑排序时,可以采用优先队列,优先输出数值较小的元素。
代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
#include <functional>
using namespace std;
#define MAXV 1000
vector<int> G[MAXV]; //临接表
int N,inDegree[MAXV]={0},ve[MAXV]={0}; //顶点数,边数,入度
int table[1000];
struct cmp{
bool operator () (int a,int b)
{return table[a]>table[b];}
};
int topoSort()
{
int num=0; //入队次数
priority_queue<int,vector<int>,cmp > q;
for(int i=0;i<N;i++)
{
if(inDegree[i]==0&&table[i]>=0)
q.push(i); //将度为0的结点入队
}
while(!q.empty())
{
int u=q.top(); //取出队首结点
if(num==0)
cout<<table[u];
else
cout<<' '<<table[u];
q.pop();
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
inDegree[v]--; //入度减1
if(inDegree[v]==0)
q.push(v); //入队
}
G[u].clear(); //清边,非必需
num++;
}
if(num == N)
return 1;
else
return 0;
}
int main()
{
cin>>N;
for(int i=0;i<N;i++)
{
scanf("%d",&table[i]);
}
//建邻接表并计算入度
for(int i=0;i<N;i++)
{
int pos=table[i]%N;
if(pos==i||table[i]<0)
continue;
else
{
int k=1;
int posN=(pos+k)%N;
inDegree[i]++;
G[pos].push_back(i);
while(posN!=i)
{
if(table[i]<0)
{
}
else
{
inDegree[i]++;
G[posN].push_back(i);
}
k++;
posN=(pos+k)%N;
}
}
}
topoSort();
return 0;
}
总结
不要忘记线性探测法中的取余运算,写完while循环要检查下里面关键元素的初始值和结束值到底和预期的是否一致。