断断续续做了一个星期。特此留念纪念/(ㄒoㄒ)/~~
POJ 3278 : http://poj.org/problem?id=3278
正确题意:原点为0,起点为n,终点为k,小人自起点走到终点的最少步数为几步。
走法有: +1,-1,乘2 三种
n,k <100000
PS: 如果起点在终点的右边,那么小人就只能 -1 的走法了
一个星期的错误经历:
起初的不明白-1操作的意义是什么...... 想只要乘2后一直在终点前面就乘2,然后慢慢的+1操作就好了。 事实证明样例5 17 都过不了。
于是明白自己的愚蠢。在算法后添加 讨论一下到乘2乘到超过终点,在倒回去。 事实证明样例还是过不了。
细细思考,才明白自己想的太蠢,果然是搜索题。每走一步都对 -1,+1,乘2 三种走法进行搜一遍。防止重复走,标记到达每个点的最少步数。
写着写着就变成递推了......每一个点的最少步数都是 能够到达此点的前面点的最少步数 加一。这不是动态规划么?
想了想有点小激动,结果写了半天都没写出来。
由于有-1,+1 操作,动态规划是问题由同类型子问题决定。而这个由-1的子问题和+1的后问题决定,没法推了.....
受不了了。想,难不成要对 100000的数组标记暴力搜吗?这样的方法是不是太渣没有逼格?而且DFS怎么写出来剪枝了还是超时......
想来想去想不出来,又不愿意用朴素办法。
一个星期后。只能无奈的百度看众位前辈的解题办法。
还真的是对 100000的数组标记搜索。 但用的是BFS......
垂头丧气的写出代码......
还有两个小插曲......
起初以为起点在终点的右边时,就将 起点与终点 swap 一下继续算。 也就是 在输入 5 17 时,与输入 17 5 时的输出是一样的。
然而5 17 输出4, 17 5 输出12 。当起点大于终点时,输出二者之差。
最后,写完了BFS。依然是错的。
实在是受不了了。不知道错在哪里。研究了很久,和别人的AC代码进行逐条比对,消耗一个晚上的时间。
终于发现。错误原因是,数据量太大,BFS的队列开为局部变量会溢出。
.......把队列改为全局变量终于TM A了。。。。。
BFS思路:
队列开始装入首点。 标记首点。
取点;三种走法,只要未溢出,并且都未标记过,就放入队列并标记; (队列里的都是前面未标记,现在刚标记的)清晰
判断终点标记是否已标记,则终止
——(重复至空) 把拓展开的点 没标的的放进去标了
上BFS代码
#include"cstdio"
#include"queue"
#include"cstring"
#include"algorithm"
using namespace std;
#define inf 100001
int book[inf];
int n,k;
queue<int>q;
int bfs()
{
memset(book,-1,sizeof book);
while(!q.empty())q.pop();
q.push(n);
book[n]=0;
while(!q.empty())
{
int t=q.front();q.pop();
for(int i=0;i<3;i++)
{
int tag;
if(i==0)tag=t*2;
else if(i==1)tag=t+1;
else tag=t-1;
if(tag<0||tag>=inf)continue;
if(book[tag]==-1)
{
book[tag]=book[t]+1;
q.push(tag);
}
if(tag==k)return book[k];
}
}
}
int main()
{
scanf("%d%d",&n,&k);
if(n>=k)printf("%d\n",n-k);
else printf("%d\n",bfs());
return 0;
}