题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6223
题意:给定长度为n的一串数字S,现在要按照一种规则寻找长度为n的数字串,使得该数字串的字典序最大。规则:从数字串S的某一个下标为x的数字出发,可以到达的下一个数字是下标为(x*x+1)%n的数字。
思路:BFS+剪枝。剪枝技巧:
1:遍历到某一层的节点时,记录已经到达过的节点,下次如果还经过就直接不考虑。
2:当前遍历到的某一层节点的数字较之前的小,直接不考虑。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<algorithm> #include<cmath> #include<vector> #include<cstring> #include<queue> using namespace std; #define INF 0x3f3f3f3f #define EPS 1e-7 typedef unsigned long long ll; const int N_MAX = 150000+10; const int MOD = 1e10+7; int n,st[N_MAX],t;//堆栈st保存当前一层所有的节点的下标 bool vis[N_MAX]; char a[N_MAX],ans[N_MAX],_max; struct Node { int index, step; Node(int index = 0, int step = 0) :index(index), step(step) {} bool operator < (const Node &b)const { if (this->step != b.step)return step > b.step; else return a[this->index] < a[b.index]; } }; void init(int &n) { memset(st, 0, sizeof(n)); t = 0; memset(vis, 0, sizeof(vis)); for (int i = 0; i < n; i++)ans[i] = '0'-1; _max = '0'-1; } void bfs() { priority_queue<Node>que; for (int i = 0; i < n; i++) { if (_max == a[i]) { que.push(Node(i, 0)); }//初始将值最大的元素节点压入队列 } int pre_step = -1,t=0; while (!que.empty()) { Node p = que.top(); que.pop(); if (pre_step != p.step) {//判断当前是第几层,如果到达新一层,之前记录销毁 pre_step = p.step; while (t)vis[st[--t]] = false; } if (ans[p.step] > a[p.index] || p.step >= n || vis[p.index])continue;//如果当前的节点value比较小或者当前节点已经走过,剪枝 ans[p.step] = a[p.index]; st[t++] = p.index; vis[p.index] = true; que.push(Node(((ll)p.index*p.index+1)%n,p.step+1)); } } int main() { int t; scanf("%d",&t); for (int cs = 1; cs <= t;cs++) { scanf("%d", &n); init(n); scanf("%s",a); for (int i = 0; i < n;i++) _max = max(_max, a[i]); bfs(); ans[n] = '