zoj 2672 DP+hash

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1672

A sequence of integer numbers a1 , a2 , ..., an is called a Fibonacci sequence if ai = ai-2+ai-1 for all i=3,4,...,n.

Given a sequence of integer numbers c1 , c2 , ..., cm you have to find its longest Fibonacci subsequence.

Input

There are several test cases in the input. The first line of each case contains  m  ( 1 <= m <= 3,000 ). Next line contains  m  integer numbers not exceeding  109  by their absolute value.
There is a new line between each case.

Output

On the first line of each case print the maximal length of the Fibonacci subsequence of the given sequence. On the second line print the subsequence itself.
There is a new line between each case.

Example

InputOutput
10
1 1 3 -1 2 0 5 -1 -1 8
5
1 -1 0 -1 -1

题目大意:求出给定序列中最长的一组子序列:a[i]+a[i+1]=a[i+2],满足Fibonacci关系。

解题思路:

               其实这是一道dp的题目,本来我们假设dp[i][j] 代表的是以a[i]和a[j]为开头的序列的长度。i从1~n而j从1~i-1,遍历,每对ij都作为相加看是否在已遍历过的i~n里有没有二者的和,如果有找出这个数的位置x,dp[j][i]=dp[i][x]+1.这样一来思路就清晰了。但是这里还有一个问题,我们整个问题下来是O(n^3)的复杂度,显然这对n==3000的数据量来说是无法接受的。因此我们在寻找a[i]+a[j]的时候运用哈希表复杂度为O(1),这样一来复杂度就降到的O(n^2), 就可以通过了。

附上hash_map的应用:http://blog.sina.com.cn/s/blog_4ac0a0d30100ukpp.html

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <hash_map>
using namespace std;
using __gnu_cxx::hash_map;
#define N 3010
int a[N];
int dp[N][N];
int n;
hash_map<int,int>mp;
hash_map<int ,int >::iterator it;
int main()
{
    int test=0;
    while(~scanf("%d",&n))
    {
        if(test!=0)
            printf("\n");
        test++;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                 dp[i][j]=1;
        mp.clear();
        int m=0,x,y;
        x=a[1];
        for(int i=n;i>=1;i--)
        {
            for(int j=1;j<i;j++)
            {
                int k=a[i]+a[j];
                it=mp.find(k);
                if(it!=mp.end())
                {
                    dp[j][i]=dp[i][it->second]+1;
                    if(dp[j][i]>m)
                    {
                        m=dp[j][i];
                        x=j;
                        y=i;
                    }
                }
            }
            mp[a[i]]=i;
        }
        if(n==1)
        {
            printf("1\n%d\n",a[1]);
            continue;
        }
        if(n==2)
        {
            printf("2\n%d %d\n",a[1],a[2]);
            continue;
        }
        if(m==0)
        {
            printf("2\n%d %d\n",a[1],a[2]);
        }
        else
        {
            printf("%d\n",m+1);
            x=a[x],y=a[y];
            printf("%d",x);
            for(int i=1;i<=m;i++)
            {
                printf(" %d",y);
                int z=x+y;
                x=y;
                y=z;
            }
            printf("\n");
        }
    }
    return 0;
}
/*
const int maxn=1000010;
const int maxd=15;
const int seed=30007;
struct HASHMAP{
    int head[seed],next[maxn],size;
    LL state[maxn];
    LL f[maxn];
    void clear(){
        size=0;
        memset(head,-1,sizeof(head));
    }
    void insert(LL st,LL ans){
        int h=st%seed;
        for (int i=head[h];i!=-1;i=next[i]){
            if (state[i]==st)
            {
                f[i]=max(f[i],ans);
                return;
            }
        }
        state[size]=st;
        f[size]=ans;
        next[size]=head[h];
        head[h]=size++;
    }
}hm[2];



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值