20200211学习

题一:

学习使用  next_permutation prev_permutation

发现函数next_permutation()是按照字典序产生排列的,并且是从数组中当前的字典序开始依次增大直至到最大字典序

比如初始数据是 1 2 3

使用next_permutation(a,a+n)  (n==3)后生成 1 3 2

连续使用后依次生成 2 1 3 | 2 3 1 | 3 1 2  | 3 2 1

当当前序列不存在下一个排列时,函数返回false,否则返回true

当 3 2 1后在使用会直接返回false 

同时他是从目前开始依次递推,所以比如数组初始是 2 1 3的话,他下一次会直接是2 3 1,所以假如需要全排列的话建议使用sort先排序一次,否则只能找出该序列之后的全排列数

此外,next_permutation(node,node+n,cmp)可以对结构体num按照自定义的排序方式cmp进行排序。

也可以对字符,因为字符的比较根本还是ascii码

实战演练 : POJ  1256

题目重点:'A'<'a'<'B'<'b'<...<'Z'<'z'.所以使用cmp自定义sort和next_permutation的排序规则就可以做出

//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define maxn 1000005
#define MAXN 1000000
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define ll long long
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a)) 
using namespace std;
char a[20];
int cmp(char a ,char b)
{
    if(tolower(a)!=tolower(b))
    return tolower(a)<tolower(b);
    return a<b;
 } 
int main()
{
    iossync
    int T;
    cin>>T;
    while(T--)
    {
        cin>>a;
        int n=strlen(a);
        sort(a,a+n,cmp);
        do{
            cout<<a<<"\n";
        }while(next_permutation(a,a+n,cmp));
    }
    return 0;
 } 

 

题二

洛谷正常刷题

普及练习场—带有技巧的搜索—P1118 数字三角形

分析:找出字典序最小的,先打表打出杨辉三角的前12行各个子项前的数,然后用dfs爆搜就行,剪下枝干,不然会tle

#include <bits/stdc++.h>
using namespace std;
int mapp[15][15]={
    { 0 },
    { 1 } , // N = 1 
    { 1 , 1 } , // N = 2
    { 1 , 2 , 1 } , // N = 3
    { 1 , 3 , 3 , 1 } , // N = 4
    { 1 , 4 , 6 , 4 , 1 } , // N = 5
    { 1 , 5 , 10, 10, 5 , 1 } , // N = 6
    { 1 , 6 , 15, 20, 15, 6 , 1 } , // N = 7
    { 1 , 7 , 21, 35, 35, 21, 7 , 1 } , // N = 8
    { 1 , 8 , 28, 56, 70, 56, 28, 8 , 1 } , // N = 9
    { 1 , 9 , 36, 84,126,126, 84, 36, 9 , 1 } , // N = 10 
    { 1 , 10, 45,120,210,252,210,120, 45, 10 , 1 } , // N = 11
    { 1 , 11, 55,165,330,462,462,330,165, 55 ,11 , 1 } }; // N = 12 
int a[15],b[15];
int flag;
int n,sum;
int dfs(int x,int y)
{
    if(x==n)
    {
        if(y==sum)
        flag=1;
        return 0;
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            if(b[i])
            continue;
            if(y+mapp[n][x]*i<=sum)
            {
                ++b[i];
                a[x+1]=i;
                dfs(x+1,y+mapp[n][x]*i);
                b[i]--;
                if(flag)
                return 0;
            }
            else
            return 0;
        }
    }
}
int main()
{
    //int n,sum;
    cin>>n>>sum;
    dfs(0,0);
    if(flag)
    for(int i=1;i<=n;i++)
    cout<<a[i]<<" ";
    cout<<"\n";
    return 0;
 } 

同样的,也可以使用next_permutation

#include <bits/stdc++.h>
using namespace std;
int mapp[15][15]={
    { 0 },
    { 1 } , // N = 1 
    { 1 , 1 } , // N = 2
    { 1 , 2 , 1 } , // N = 3
    { 1 , 3 , 3 , 1 } , // N = 4
    { 1 , 4 , 6 , 4 , 1 } , // N = 5
    { 1 , 5 , 10, 10, 5 , 1 } , // N = 6
    { 1 , 6 , 15, 20, 15, 6 , 1 } , // N = 7
    { 1 , 7 , 21, 35, 35, 21, 7 , 1 } , // N = 8
    { 1 , 8 , 28, 56, 70, 56, 28, 8 , 1 } , // N = 9
    { 1 , 9 , 36, 84,126,126, 84, 36, 9 , 1 } , // N = 10 
    { 1 , 10, 45,120,210,252,210,120, 45, 10 , 1 } , // N = 11
    { 1 , 11, 55,165,330,462,462,330,165, 55 ,11 , 1 } }; // N = 12 
int a[15],b[15];
int n,sum;
int cmp(int a,int b)
{
    return a>b;
}
int main()
{
    //int n,sum;
    cin>>n>>sum;
    for(int i=1;i<=n;i++)
    a[i]=i;
    do{
        int add=0;
        for(int i=1;i<=n;i++)
        {
            add+=a[i]*mapp[n][i-1];
            if(add>sum)//剪枝的关键,从这里开始的add已经大于sum了,那么以他开头的排列全部可以省去 
            {
                sort(a+i+1,a+n+1,cmp);
                break;
            }
        }
        if(add==sum)
        {
            for(int i=1;i<=n;i++)
            cout<<a[i]<<" ";
            cout<<"\n";
            return 0;
         } 
    }while(next_permutation(a+1,a+n+1));
    return 0;
 } 

 

题三

紧跟题二的训练场 P1434

分析:傻逼题,一开始看错题意了,以为求最长的轨道的最高点到最低点的距离,2发20分,思考了半天为啥错,才发现题意不对

动态规划

#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[505][505];
int bp[505][505];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int dfs(int x,int y)
{
    if(bp[x][y]>=0)
    return bp[x][y];
    //int flag=1;
    bp[x][y]=1; 
    for(int i=0;i<4;i++)
    {
        int x1=x+dx[i],y1=y+dy[i];
        if(x1<0 || x1>=n || y1<0 || y1>=m)
        continue;
        if(a[x1][y1]<a[x][y])
        {
            //flag=0;
            //bp[x][y]=max(bp[x][y],dfs(x1,y1)+a[x][y]-a[x1][y1]);看错题意了
            bp[x][y]=max(bp[x][y],dfs(x1,y1)+1);
        }
    }
    //if(flag)
    //bp[x][y]=a[x][y];
    return bp[x][y];
}
int main()
{
    memset(bp,-1,sizeof(bp));
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>a[i][j];
        }
    }
    int maxx=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            maxx=max(dfs(i,j),maxx);
        }
    }
    cout<<maxx<<"\n";
    return 0;
}

试着用dp重新写了一个,并结合了优先队列

#include <bits/stdc++.h>
using namespace std;
int n,m; 
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
struct node{
    int i1,j1,h1,sum1;
}a[105];
int cmp(node x,node y)
{
    return x.h1<y.h1;
 }
int mapp[105][105];
int sum[105][105];
struct cmp1{
    bool operator()(node x,node y){
        return x.h1>y.h1;
    }
};//优先队列小的在前面
priority_queue<node,vector<node>,cmp1>q;
int main()
{
    cin>>n>>m;
    //int num=0;
    //第一种方法按顺序读入,然后使用sort排序,然后查找 
//    for(int i=0;i<n;i++)
//    {
//        for(int j=0;j<m;j++)
//        {
//            cin>>a[num].h1;
//            a[num].i1=i;
//            a[num++].j1=j;
//        }
//    }
//    sort(a,a+num,cmp); 
    //第二种方法,使用优先队列
     for(int i=0;i<n;i++)
     {
         for(int j=0;j<m;j++)
         {
             sum[i][j]=1;//本身长度为1 
             cin>>mapp[i][j];
             node w;
             w.h1=mapp[i][j],w.i1=i,w.j1=j;
             w.sum1=0;
             q.push(w);
         }
     }
     int maxn=0;
     while(!q.empty())
     {
         node qwe=q.top();
         int x=qwe.i1,y=qwe.j1;
         q.pop();//出队
        for(int i=0;i<4;i++)
            {
                int x1=x+dx[i],y1=y+dy[i];
                if(x1<0 || x1>=n || y1<0 || y1>=m)
                continue;
                if(mapp[x1][y1]<mapp[x][y])
                {
                    sum[x][y]=max(sum[x][y],sum[x1][y1]+1);
                }
            } 
        maxn=max(maxn,sum[x][y]);
     }
     cout<<maxn<<"\n";
     return 0;
}
View Code

 

题四

洛谷P1433 吃奶酪

分析:emm,先打了一个暴力dfs,然后90分,最后一组会tle

#include <bits/stdc++.h>
using namespace std;
typedef pair<double,double> P;
P a[20];
int n;
double fact(P x,P y)
{
    return sqrt((x.first-y.first)*(x.first-y.first)+(x.second-y.second)*(x.second-y.second));
}
int vis[20];//标记奶酪是否已经被拾取
double ans=1000000000.0,now,dis[20][20]; 
void dfs(int pos,int num)
{
    //cout<<pos<<" "<<num<<" "<<now<<"\n";
    if(now>ans)
    return ;
    if(num==n)
    {
        ans=min(ans,now);
        return ;
    }
    vis[pos]=1;
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            now+=dis[pos][i];
            dfs(i,num+1);
            now-=dis[pos][i];
        }
    }
    vis[pos]=0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //cin>>n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        //cin>>a[i].first>>a[i].second;
        scanf("%lf %lf",&a[i].first,&a[i].second);
    }
    a[0].first=0,a[0].second=0;
    for(int i=0;i<=n;i++)//预处理2点距离 
    {
        for(int j=0;j<=n;j++)
        {
            //dis[i][j]=fact(a[i],a[j]);
            dis[i][j]=sqrt((a[i].first-a[j].first)*(a[i].first-a[j].first)+(a[i].second-a[j].second)*(a[i].second-a[j].second));
        }
    }
    dfs(0,0);
    printf("%.02lf\n",ans);
    //cout<<ans<<"\n";
    return 0;
}
View Code

那没办法了,

#include <bits/stdc++.h>
using namespace std;
double x[20],y[20],dis[20][20];
double num[20][40000];
int main() {
    int n;
    cin>>n;
    memset(num,127,sizeof(num));
    // 15个数字 (1<<15)-1
    //dis[x][y]  从x遍历到y的距离最小值
    //dis[x][y]=min(dis[x][y],dis[a][y-1<<(i-1)]+num[a][x]
    for(int i=1; i<=n; i++) {
        //cin>>x[i]>>y[i];
        scanf("%lf %lf",&x[i],&y[i]);
    }
    //优先预处理各个位置的距离,方便后续计算
    x[0]=0,y[0]=0;
    for(int i=0; i<=n; i++) {
        for(int j=0; j<=n; j++) {
            dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
        }
    }
    int maxn=(1<<n)-1;
    for(int s=1;s<=maxn;s++)//00000001
    {
        for(int i=1;i<=n;i++)
        {
            if((s&(1<<(i-1)))==0)
            continue;
            if(s==(1<<(i-1)))
            {
                num[i][s]=0;
                continue;
            }
                for(int j=1;j<=n;j++)
                {
                    if(s&(1<<(j-1))==0)
                    continue;
                    if(i==j)
                    continue;
                        num[i][s]=min(num[i][s],num[j][s-(1<<(i-1))]+dis[i][j]);
                }
        }
     }
     double ans=1000000000;
     for(int i=1;i<=n;i++)
     {
         ans=min(ans,num[i][(1<<n)-1]+dis[i][0]);
     }
     printf("%.2lf\n",ans);
     return 0;
}

使用状压,这题不能用一般的dfs剪枝,数据似乎加强了,题解区的dfs全部过不去(一开始我还以为是我的dfs剪得不对,改了好久好久好久。。。)

 

题五

洛谷P1020 导弹拦截

分析:LIS裸题,求一遍LIS,再反过来再求一遍就好了,记得第二遍那个不是完全递减,可以存在相同的,所以lower_bound要改成upper_bound

刚好复习下LIS的模板

#include <bits/stdc++.h>
using namespace std;
int dp[200000];
int a[200000];
#define INF 100000000
int main()
{
    //LIS部分 
    int n=0;
    //cin>>n;
    fill(dp,dp+n,INF);
    //for(int i=0;i<n;i++)
    //{
    //    cin>>a[i];
    //}
    while(cin>>a[n++])
    ;
    n--;
    int num=0;
    dp[0]=a[0];
    for(int i=1;i<n;i++)
    {
        if(a[i]>dp[num])
        {
            dp[++num]=a[i];
        }
        else
        {
            *lower_bound(dp,dp+num,a[i])=a[i];
        }
    }
    //cout<<num+1<<"\n";
    for(int i=0;i<(n+1)/2;i++)
    {
        swap(a[i],a[n-1-i]);
    }
    int sum=0;
    fill(dp,dp+n,INF);
    dp[0]=a[0];
    for(int i=1;i<n;i++)
    {
        if(a[i]>=dp[sum])
        {
            dp[++sum]=a[i];
        }
        else
        {
        //    cout<<*upper_bound(dp,dp+n,a[i])<<"\n";
            *upper_bound(dp,dp+n,a[i])=a[i];
        }
    }
    cout<<sum+1<<"\n"<<num+1<<"\n";
    return 0;
}

 

posted @ 2020-02-11 22:15  wwldx  阅读(90)  评论(0)    收藏  举报