Addition Chains(加法链)

poj 2248

题目大意:给出一系列数的最后一个数,默认第一个数是1,求一系列数字,要求除第一个数外,其它的每个数都是前边两个数的和(可以是同一个数加上本身),求最少需要多少个数就能加到给定的数 ,输出,过程

解决:bfs+路径记录,记录路径可以在结构体中加入当前地址,值,和从哪个扩展来的,三个数就够了。本题,最开始思考的时候,想着bfs一般都是要用到vis数组记录是否走过,以避免重复而导致陷入死循环, 但是,当用了vis数组后,新的问题来了,比如数n,有好多条路劲到达数n的,但是,如果第一个进队列下次遇到n不进队列了,会导致若最终求的是m,不一定第一个进队列的刚好是到m最短的,后来仔细想了下,其实不会重复的。因为,本题从一种状态转移的另一种状态的方式是加上之前路径上的每个点,每个都不一样,都是从不同的路径下来的,虽然最终加了之后的结果一样,不会造成死循环。由于要记录路径,不能用循环队列,就必把数组开的足够大,开始开到10000,re了,加了个0,就过了。

#include <iostream>
#include <cstring>
#include <queue>
#include <string>
#include <cstdio>
using namespace std;
int n;
struct node
{
    int id;
    int val;
    int pre;
    node(){}
    node(int i,int v,int p):id(i),val(v),pre(p){}
}q[100000];

void print(int x)
{
    if(x!=-1)
    {
        print(q[x].pre);
        printf("%d ",q[x].val);
    }
}
void bfs()
{
    if(n==1){puts("1"); return;} 
    int front=0,rear=0;
    q[rear++]=node(0,1,-1);
    node now,next;
    while(rear!=front)    
    {
        now=q[front++];
        for(int i=now.id; i!=-1; i= q[i].pre)
        {
            int t=now.val+q[i].val;
            if(t==n){print(now.id); printf("%d\n",t); return;}
            if(t <= n )
            {
                q[rear]=node(rear++, t, now.id);
             }
        }
    }
}
int main()
{
     while(scanf("%d",&n),n)
     {
          bfs();  
     }
    system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/hpustudent/p/2180808.html