timus1965(不错的贪心)

题意是:给你一个1-n的排列,要你把这个排列分成两个序列,且这个两个序列都满足单调性。

题解:

1.首先假设找出的两个序列都是单调递增的(都是单调递减的同理)

那么很容易可以想到,将新加入的数放入到某个序列尾端,使得另一个序列尾端的数尽量小。

2.如果最后的两个序列为一个递增一个递减。

这种情况下,有一种眼光稍微长远一些的贪心策略。

假设当前要加入的数g[x],如果g[x]既可以放入单增序列中也可以放入单减序列中,则与g[x+1]比较。

if(g[x]>g[x+1]) 把g[x]放入单减序列中

else 把g[x]放入单增序列中

为什么这样贪心就行了?

可以做一个假设,当g[x]>g[x+1],我们却把g[x]放入单增序列中,则g[x]只能放入单减序列,最后得出的两个序列的尾部为:

xxxxg[x]    (单增序列)        。。。。。。。。。方法一

xxxxxxg[x+1] (单减序列)

而当我们把g[x]放入单减序列时,此时g[x+1]可能放入单增序列中,一定可以放入单减序列中,

1.如果g[x+1] 放入单减序列中,得出两个序列尾部为:

xxxX        (单增序列)    。。。。。。。。。方法二

xxxxxxg[x]g[x+1]  (单减序列)

而X<g[x] ,所以下面这种方法得出的结果一定优于方法一。

2.如果g[x+1]能放入单增序列,放入其中得出的两个序列尾部为:

xxxxg[x+1]  (单增序列)        。。。。。。。。。方法三

xxxxxxg[x]  (单减序列)

因为g[x]>g[x+1],所以结果一定优于方法一。

把眼界放开,即使是贪心也能贪的漂亮!

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxN 100005
const int inf=~0U>>1;
int s1[maxN];
int f[maxN][2];
int N,len1,len2;
bool judge1()
{
    f[0][0]=f[0][1]=-1;
    len1=len2=0;
    for(int i=1;i<=N;i++)
    {
        if(s1[i]<f[len1][0]&&s1[i]<f[len2][1])
            return false;
        else if(s1[i]>f[len1][0]&&s1[i]<f[len2][1])
            f[++len1][0]=s1[i];
        else if(s1[i]<f[len1][0]&&s1[i]>f[len2][1])
            f[++len2][1]=s1[i];
        else
        {
            if(f[len2][1]>f[len1][0]) f[++len2][1]=s1[i];
            else f[++len1][0]=s1[i];
        }
    }
    if(len1==N) f[++len2][1]=f[len1--][0];
    return true;
}
bool judge2()
{
    f[0][0]=f[0][1]=inf;
    len1=len2=0;
    for(int i=1;i<=N;i++)
    {
        if(s1[i]>f[len1][0]&&s1[i]>f[len2][1])
            return false;
        else if(s1[i]>f[len1][0]&&s1[i]<f[len2][1])
            f[++len2][1]=s1[i];
        else if(s1[i]<f[len1][0]&&s1[i]>f[len2][1])
            f[++len1][0]=s1[i];
        else
        {
            if(f[len2][1]<f[len1][0]) f[++len2][1]=s1[i];
            else f[++len1][0]=s1[i];
        }
    }
    if(len1==N) f[++len2][1]=f[len1--][0];
    return true;
}
bool judge3()
{
    len1 = len2 = 0;
    f[len1][0]=-1;
    f[len2][1]=inf;
    for(int i=1;i<=N;i++)
    {
        if(s1[i]<f[len1][0]&&s1[i]>f[len2][1]) return false;
        else if(s1[i]>f[len1][0]&&s1[i]<f[len2][1])
        {
            if(i==N) f[++len1][0]=s1[i];
            else if(s1[i+1]>s1[i]) f[++len1][0]=s1[i];
            else f[++len2][1]=s1[i];
        }
        else if(s1[i]>f[len1][0])
            f[++len1][0]=s1[i];
        else
            f[++len2][1]=s1[i];
    }
    return true;
}
int main()
{
    scanf("%d",&N);
    for(int i=1,j=N;i<=N;i++,j--)
    {
        scanf("%d",&s1[i]);
    }
    if(judge1())
    {
        printf("%d %d
",len1,len2);
        for(int i=1;i<=len1;i++) printf("%d%c",f[i][0],i==len1?'
':' ');
        for(int i=1;i<=len2;i++) printf("%d%c",f[i][1],i==len2?'
':' ');
        return 0;
    }
    if(judge2())
    {
        printf("%d %d
",len1,len2);
        for(int i=1;i<=len1;i++) printf("%d%c",f[i][0],i==len1?'
':' ');
        for(int i=1;i<=len2;i++) printf("%d%c",f[i][1],i==len2?'
':' ');
        return 0;
    }
    if(judge3())
    {
        printf("%d %d
",len1,len2);
        for(int i=1;i<=len1;i++) printf("%d%c",f[i][0],i==len1?'
':' ');
        for(int i=1;i<=len2;i++) printf("%d%c",f[i][1],i==len2?'
':' ');
        return 0;
    }
    printf("Fail
");
    //print1(dp1[len1]);
    //printf("
");
    //print2(dp2[len2]);
    return 0;
}

另加一个,我自己想的丑陋的贪心。。。

//
//  main.cpp
//  timus1965
//
//  Created by 陈加寿 on 16/3/16.
//  Copyright © 2016年 chenhuan001. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <map>
#include <set>
#include <math.h>
#include <algorithm>
using namespace std;
#define N 100100

int g[N],tg[N];
int ans1[N],ans2[N];
int cnt1,cnt2;
int n;
int b1,d1,b2,d2;

int fuc()
{
    cnt1 = cnt2 =0;
    //->
    ans2[0] = 0;
    ans1[ ++cnt1 ] = g[1];
    for(int i=2;i<=n;i++)
    {
        if(g[i]<ans1[cnt1] && g[i]<ans2[cnt2])
        {
            return 0;
        }
        //否则选尽量大的一边
        if(g[i]>ans1[cnt1]) ans1[++cnt1]=g[i];
        else ans2[++cnt2]=g[i];
    }
    return 1;
}

int fuc1()
{
    cnt1 = cnt2 =0;
    //<-
    ans2[0] = n+1;
    ans1[ ++cnt1 ] = g[1];
    for(int i=2;i<=n;i++)
    {
        if(g[i]>ans1[cnt1] && g[i]>ans2[cnt2])
        {
            return 0;
        }
        //否则选尽量小的一边
        if(g[i]<ans1[cnt1]) ans1[++cnt1]=g[i];
        else ans2[++cnt2]=g[i];
    }
    return 1;
}

int test1(int b,int d)
{
    if( tg[d]<b1 || tg[d]>d1 ) return 0;// g[i]无法放入ans1中
    //把(b,d)间的数全部放入ans2中去
    //首先保证(b,d)之间是递减的
    if(b+1 == d)
    {
        ans1[++cnt1] = d;
        b1 = tg[d];
        return 1;
    }
    for(int i=d-2;i>b;i--)
    {
        if(tg[i]<tg[i+1]) return 0;//并不递减
    }
    if( tg[d-1]>b2 && tg[b+1]<d2 )
    {
        for(int i=d-1;i>b;i--)
            ans2[++cnt2] = i;
        ans1[++cnt1] = d;
        d2=tg[d-1];
        b1 = tg[d];
        return 1;
    }
    else return 0;
}

int test2(int b,int d)
{
    if(tg[b]<b2 || tg[b]>d2) return 0;
    if(b+1 == d)
    {
        ans2[++cnt2] = b;
        b2 = tg[b];
        return 1;
    }
    for(int i=b+1;i<d-1;i++)
    {
        if(tg[i]>tg[i+1]) return 0;
    }
    if(tg[b+1]>b1 && tg[d-1]<d1)
    {
        for(int i=d-1;i>b;i--)
            ans1[++cnt1] = i;
        ans2[++cnt2] = b;
        d1 = tg[b+1];
        b2 = tg[b];
        return 1;
    }
    else return 0;
}

int solve()
{
    int b=0,d=n+1;
    b1=0,d1=n+1;
    b2=0,d2=n+1;
    //并不需要set
    for(int i=1;i<=n;i++)
    {
        if( g[i]<b || g[i]>d) continue; //已经处理过的,不再处理
        if(g[i]-b < d-g[i])
        {
            //靠左,g[i]放入ans1中
            if( test1(b,g[i])==1 )
            {
                //如果
                b = g[i];
            }
            else if(test2(g[i],d)==1)
            {
                d = g[i];
            }
            else return 0;//两个测试都不过 直接返回不行.
        }
        else
        {
            //靠右
            if(test2(g[i],d)==1)
            {
                d=g[i];
            }
            else if(test1(b, g[i])==1)
            {
                b=g[i];
            }
            else return 0;
        }
    }
    return 1;
}

int cmp(int x,int y)
{
    return x>y;
}

int main() {
    cin>>n;
    
    for(int i=1;i<=n;i++)
    {
        scanf("%d",g+i);
        tg[ g[i] ] = i;
    }
    g[0]=0; g[n+1]=n+1;
    tg[0]=0; tg[n+1]=n+1;
    cnt1 = cnt2 = 0;
    int flag=0;
    //step one  tha same direction
    if( fuc() || fuc1() )
    {
        flag=1;
    }
    if(flag == 0)
    {
        // step two the different direction
        cnt1 = cnt2 =0;
        flag = solve();
        //最后再sort一下
        sort(ans1+1,ans1+1+cnt1);
        sort(ans2+1,ans2+1+cnt2,cmp);
    }
    if(flag == 0)
    {
        printf("Fail
");
    }
    else
    {
        //输出答案
        if(cnt1==n)
        {
            ans2[++cnt2] = ans1[cnt1--];
        }
        if(cnt2==n)
        {
            ans1[++cnt1] = ans2[cnt2--];
        }
        cout<<cnt1<<" "<<cnt2<<endl;
        for(int i=1;i<=cnt1;i++) printf("%d ",ans1[i]);
        printf("
");
        for(int i=1;i<=cnt2;i++) printf("%d ",ans2[i]);
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chenhuan001/p/5289887.html