借鉴自:http://blog.csdn.net/queuelovestack/article/details/52970866
Fxx and game
Accepts: 74
Submissions: 1857
Time Limit: 3000/1500 MS (Java/Others)
Memory Limit: 131072/65536 K (Java/Others)
问题描述
青年理论计算机科学家Fxx给的学生设计了一款数字游戏。 一开始你将会得到一个数X,每次游戏将给定两个参数k,t, 任意时刻你可以对你的数执行下面两个步骤之一: 1.X=X−i(1<=i<=t)。 2.若X为k的倍数,X=X/k。 现在Fxx想要你告诉他最少的运行步骤,使X变成1。
输入描述
第一行一个整数T(1≤T≤20)表示数据组数。 接下来T行,每行三个数X,k,t(0≤t≤106,1≤X,k≤106) 数据保证有解。
输出描述
输出共T行。
每行一个整数表示答案。
输入样例
2 9 2 1 11 3 3
输出样例
4 3
分析:做题时错误使用了贪心导致wa了十分智障。阅读别人博客发现有bfs与单调队列两种做法。
BFS做法:遍历状态,将当前状态所能达到的所有可能状态压栈遍历。进行适当剪枝,遍历过的无需再次遍历即可。
单调队列做法:用单调队列维护可选状态,
1002 Fxx and game
设Fi表示将i变为1的最少步骤,如果k∣i,Fi=min{Fj,Fki},否则Fi=min{Fj},其中i−t≤j≤i−1。
用单调队列维护一下就好了。
时间复杂度O(n)。
题解写的十分简略,但意思挺明显的,维护单调队列的意义是为求出当前状态的最优解做准备,不过做题时并没有想到单调队列,用的也很少。
//BFS
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const long long N=1000005;
const long long mod=1e9;
const double PI=acos(-1.0);
typedef long long ll;
struct node {
int x,c;
node(){};
node(int _x,int _c):x(_x),c(_c){}
};
bool v[N];
int bfs(int x,int k,int t) {
if (k==1&&t) {
return (x+t-2)/t;
}
int minn;
node u;
queue<node> q;
for (int i=1; i<=x; i++) {
v[i]=false;
}
q.push(node(x,0));
v[x]=true;
while (!q.empty()) {
u=q.front();
q.pop();
if (u.x==1) {
return u.c;
}
if (u.x%k==0&&!v[u.x/k]) {
q.push(node(u.x/k, u.c+1));
v[u.x/k]=true;
}
minn=min(t,u.x-1);
for (int i=minn; i>=1; i--) {
if (!v[u.x-i]) {
q.push(node(u.x-i, u.c+1));
v[u.x-i]=true;
}
else break;
}
}
return 0;
}
int main() {
int ti;
cin>>ti;
int x,t,k;
while (ti--) {
cin>>x>>k>>t;
cout<<(bfs(x, k, t))<<endl;
}
return 0;
}
//单调队列
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const long long N=1000005;
const long long mod=1e9;
const double PI=acos(-1.0);
typedef long long ll;
int ans[N],p[N];
int main() {
int ti;
cin>>ti;
int x,t,k;
while (ti--) {
cin>>x>>k>>t;
if (k==1&&t) {
cout<<(x+t-2)/t<<endl;
continue;
}
int head,tail;
ans[1]=0;p[1]=1;head=tail=1;
for (int i=2; i<=x; i++) {
if (i%k==0) {
ans[i]=ans[i/k]+1;
} else {
ans[i]=INF;
}
while (head<=tail&&i-p[head]>t) {
head++;
}
if (head<=tail) {
ans[i]=min(ans[i], ans[p[head]]+1);
}
while (head<=tail&&ans[p[tail]]>=ans[i]) {
tail--;
}
p[++tail]=i;
}
cout<<ans[x]<<endl;
}
return 0;
}