• 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<<"
    ";
            }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<<"
    ";
        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<<"
    ";
                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<<"
    ";
        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<<"
    ";
         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<<"
    ";
        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
    ",ans);
        //cout<<ans<<"
    ";
        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
    ",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<<"
    ";
        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])<<"
    ";
                *upper_bound(dp,dp+n,a[i])=a[i];
            }
        }
        cout<<sum+1<<"
    "<<num+1<<"
    ";
        return 0;
    }
  • 相关阅读:
    C++逐行读取文本文件的正确做法
    <Android Framework 之路>Android5.1 Camera Framework(一)
    zeromq-4.1.2在windows下的编译
    Duilib应用修改程序图标方法
    gdal集成kml库的做法
    使用DWR实现JS调用服务端Java代码
    DirectUI界面编程(六)实现右键弹出菜单
    如何设计系统的错误码及错误信息
    TCP协议格式
    UDP协议
  • 原文地址:https://www.cnblogs.com/wwl0702/p/12291843.html
Copyright © 2020-2023  润新知