zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    noi 2011 noi嘉年华 动态规划
    最小乘积生成树
    noi 2009 二叉查找树 动态规划
    noi 2010 超级钢琴 划分树
    noi 2011 阿狸的打字机 AC自动机
    noi 2009 变换序列 贪心
    poj 3659 Cell Phone Network 动态规划
    noi 2010 航空管制 贪心
    IDEA14下配置SVN
    在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
  • 原文地址:https://www.cnblogs.com/wwl0702/p/12291843.html
Copyright © 2011-2022 走看看