zoj1108 FatMouse's Speed

给你每个物体两个参数,求最长的链要求第一个参数递增,第二个参数递减,要求输出任意最长路径。

首先第一反应根据第二个参数排个序,然后不就是最长上升子序列的问题吗?

O(nlogn)的复杂度,当然这样可以写,写法也不难。

然后发现这个还是个DAG,也可以用拓扑排序来搞定,输出最长路径,复杂度O(n*n),更新的时候需要更新并记录每个点的前节点,最后倒序输出。

第二种就当练练手吧

先上第二种代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
int d;
struct node
{
    int x,y;
}h[1005];
vector<int> t[1005];
int deg[1005];
queue<int> q;
int g[1005];
int ans=0;
int res=-1;
int dp[1005];
vector<int> s;
void tp()
{
    for(int i=0;i<d;i++)
    {
        if(deg[i]==0)
        {
            dp[i]=1;
               q.push(i);
        }
    }
    while(!q.empty())
    {
        int xx=q.front();
        if(dp[xx]>ans)
        {
            ans=dp[xx];
            res=xx;
        }
        q.pop();
        for(int i=0;i<t[xx].size();i++)
        {
            int w=t[xx][i];
            deg[w]--;
            if(dp[w]<dp[xx]+1)
            {
                dp[w]=dp[xx]+1;
                g[w]=xx;
            }
            if(deg[w]==0)
             q.push(w);
        }
    }
}

int main()
{
    //freopen("input.txt","r",stdin);
    int a,b;
    memset(g,-1,sizeof(g));
   while(scanf("%d%d",&a,&b)==2)
   {
       h[d].x=a;
       h[d].y=b;
       d++;
   }
   for(int i=0;i<d;i++)
     for(int j=0;j<d;j++)
   {
       if(h[i].x<h[j].x&&h[i].y>h[j].y){
        t[i].push_back(j);
        deg[j]++;
       }
   }
   tp();
   printf("%d\n",ans);
   s.push_back(res+1);
   while(g[res]!=-1)
   {
      s.push_back(g[res]+1);
       res=g[res];
   }
   int len=s.size();
   for(int i=len-1;i>=0;i--)
    printf("%d\n",s[i]);
}

第一种代码稍后补上:

参考http://blog.csdn.net/dangwenliang/article/details/5728363

原理:O(N*N)的,一维,设dp[i]为以第i位为结尾的最长长度,dp[i]=max(dp[j])+1(j<i),然后记录前缀,输出路径。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
int d;
struct node
{
    int x,y,r;
}h[1005];
int hh[1005];
int g[1005];
vector<int> t;
bool cmp(node a,node b)
{
    if(a.y>b.y)
    return 1;
    return 0;
}
int f[1005];
int ans,res;
int main()
{
    //freopen("input.txt","r",stdin);
    int a,b;
    memset(g,-1,sizeof(g));
    while(scanf("%d%d",&a,&b)==2)
   {
       h[d].x=a;
       h[d].y=b;
       h[d].r=d;
       d++;
   }
   sort(h,h+d,cmp);
   hh[0]=1;
   int res=-1;
   ans=0;
   for(int i=1;i<d;i++)
   {
       hh[i]=1;
       for(int j=0;j<i;j++)
       {
           if(h[i].x>h[j].x&&hh[i]<hh[j]+1)
           {
               hh[i]=hh[j]+1;
               g[i]=j;
               if(hh[i]>res)
               {
                   ans=i;
                   res=hh[i];
            }
        }
    }
   }
   printf("%d\n",res);
   t.push_back(ans);
   while(g[ans]!=-1)
   {
         t.push_back(g[ans]);
         ans=g[ans];
   }
   int len=t.size();
   for(int i=len-1;i>=0;i--)
   {
       printf("%d\n",h[t[i]].r+1);
   }
}

然后来O(nlogn)算法。

首先能这么做,要满足dp的两个根本原则:1.无后效性,每一个点的状态都由其前面的点决定

                                                       2.每一步都是当前那一个整体最优。

    我们必须用到二分,但是这个前面的点的序列是不连续的,所以我们需要选出前面的点中每一步中的最优,来组成一个"标杆队列",因为对于数和数之间的前后关系是重要的,但对于当前的数,前面的数的前后关系是不重要的,如果每一次二分,dp的同时维护那个"标杆队列",我们可以保证那个队列是最优的,那么下一个点也会是最优的,也可以保证结果是最优的。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
int d=1;
struct node
{
    int x,y,r;
}h[1005];
int ans[1005];
int hh[1005];
int dp[1005];
bool cmp(node a,node b)
{
    if(a.y>b.y)
    return 1;
    else if(a.y==b.y&&a.x>b.x)
    return 1;
    return 0;
}

int main()
{
    //freopen("input.txt","r",stdin);
    int a,b;
    while(scanf("%d%d",&a,&b)==2)
   {
       h[d].x=a;
       h[d].y=b;
       h[d].r=d;
       d++;
   }
   sort(h+1,h+d,cmp);
   for(int i=1;i<d;i++)
   ans[i]=10005;
   int len=0;
   for(int i=1;i<d;i++)
   {
       int t=lower_bound(ans+1,ans+d,h[i].x)-ans;
       ans[t]=h[i].x;
       dp[i]=t;
       len=max(len,t);
   }
   printf("%d\n",len);
   int cc=len;
   int res=0;
   int f=10005;
   for(int i=d-1;i>0;i--)
   {
         if(len==0)
            break;
        if(dp[i]==len&&h[i].x<f)
         {
        hh[res++]=i;
           len--;
           f=h[i].x;
        }
   }
   for(int i=res-1;i>=0;i--)
  {
        printf("%d\n",h[hh[i]].r);
  }
}
posted @ 2015-10-21 14:35  acliang  阅读(197)  评论(0编辑  收藏  举报