• SRM 547 DIV2


    250pt

    数学模型:

      求顶角是120度的等腰三角形的面积

    分析:

      L*L*sqrt(3.0)/4.0,

      计算的时候为了提高精度,先乘后除。

     

    View Code
    class MinimalTriangle 
    { 
            public: 
            double maximalArea(int length) 
            { 
                    double l=length,t=sqrt(3.0);
        return l*l*t/4.0;
            } 
            
    }; 

     

    500pt

    数学模型:

    给定n组点,每组横坐标相同,第一组:(0,1)(0,2)......(0,h[0]);.......第组:((n-1)*w,1),((n-1)*w,2)......((n-1)*w,h[n-1]),相邻两组的的横坐标相差w。在每组中任选一个点,连接相邻两组所选的点,求这条折线的总长。

    分析:比赛时猜想贪心,但证明不了,赛后证明是错的,还是用DP稳妥点

      1,枚举每组的每个点

        dp[i][j]表示选定第i组纵坐标为j的点时最长折线长度

        dp[i][j]=(dp[i-1][k],hypot(k-j,w))(1<=k<=h[i-1]);复杂度O(N^3)

      2,赛后看有人是贪心加动态规划做的,每次只用考虑每组的最高点和最低点。

        和它们之间的状态转移,复杂度是O(n)

    结:SRM比赛中,在时间限制内,编写出尽量正确且容易编写的代码,正确和短码的优先级比效率要高

      此方法可扩展到二维?

     

    枚举+动态规划

    O(n^3)
    class PillarsDivTwo 
    { 
            public: 
            double maximalLength(vector <int> h, int w) 
            { 
                int i,j,k,n=h.size();
                double dp[60][110]={0};
                if(n==1)
                    return 0.0;
                for(i=1;i<n;i++)
                    for(j=1;j<=h[i];j++)
                        for(k=1;k<=h[i-1];k++)
                            dp[i][j]=max(dp[i][j],dp[i-1][k]+hypot(abs(j-k)*1.0,w*1.0));
                for(j=k=1;j<=h[n-1];j++)
                    if(dp[n-1][j]>dp[n-1][k])
                        k=j;
                return dp[n-1][k];
            } 
            
     
    }; 

    贪心+动态规划

    O(N)
    class PillarsDivTwo 
    { 
            public: 
            double maximalLength(vector <int> h, int w) 
            { 
                int i,j,k,n=h.size();
                double dp[111][2]={0};
                for(i=1;i<n;i++)
                {
                    dp[i][0]=max(dp[i-1][0]+w,dp[i-1][1]+hypot(h[i-1]-1,w));
                    dp[i][1]=max(dp[i-1][0]+hypot(h[i]-1,w),dp[i-1][1]+hypot(1.0*abs(h[i-1]-h[i]),w));
                }
                return max(dp[n-1][0],dp[n-1][1]);
            } 
            
     
    }; 

    1000pt

    数学模型:

      给定一个数值范围是1100的整数集合,求一个子集,使元素互质且个数最多。

     

    分析:比赛的时候没想太多,直接深度优先搜索枚举每个子集,再加优化。但是犯了一个致命错误:1左移的结果是long long,应该是强制转为long long ,(long long)1;赛后改了但是超时,看别人代码居然是状态压缩动态规划,我当时想过但觉得会超时。

      重新读题,发现没有充分利用范围是1100这个条件,再考虑互质的本质:即有除1以外的公约数,任何整数都可以由质数的连乘组成,那么互质就是有公约数,而且公约是是质数,即可以用质数的集合来表示这些整数,24,可用{2,3},整数的互质就可用交集为空来表示,而这些集合最多有25个元素(100以内有25个质数),但是状态数太多,会超时;再看50以上的质数与所有其它的数都互质,所以可以预处理,那么只剩下15个,集合可用一个整数(0~(1<<15)-1)表示,每个二进制位表示一个元素,1没有该元素,0表示已有该元素。

     

    结:读题要仔细,充利用题目条件,条件不同,算法完全不同

    超时的深搜
    class RelativelyPrimeSubset 
    { 
            public:
            long long n,b[55];
            int ans;
            int gcd(int a,int b)
            {
                return b?gcd(b,a%b):a;
            }
            void DFS(long long k,int cnt,long long t)
            {
                if(k==n)
                {
                    ans=max(ans,cnt);
                    return ;
                }
                if(cnt+n-k<=ans)
                    return ;
                if(t&((long long)1<<k))
                    DFS(k+1,cnt+1,t&b[k]);
                DFS(k+1,cnt,t);
            }
            int findSize(vector <int> a) 
            { 
                    long long i,j;
                    n=(long long)a.size();
                    ans=1;
                    for(i=0;i<n;i++)
                        for(j=0,b[i]=0;j<n;j++)
                            if(gcd(a[i],a[j])==1)
                                b[i]|=((long long)1<<j);
                    for(i=0;i<n;i++)
                        DFS(i+1,1,b[i]);
                    return ans;
            } 
            
     
    }; 

     O(N*(1<<15))

    状态压缩DP
    class RelativelyPrimeSubset 
    { 
           public:
        int f[1<<15];
            int findSize(vector <int> S) 
            {
                int i,j,k,n,m,ret,empty,c[51],a[111]={0},p[111],d[51];
                bool b[51]={false};
                for(i=2;i<100;i++)
                    if(!a[i])
                    {
                        for(j=i+i;j<=100;j+=i)
                            a[j]=1;
                    }
                m=0;
                sort(S.begin(),S.end());
                if(S[0]==1)
                    m++,S.erase(S.begin());
                n=S.size();
                for(i=0;i<n;i++)
                    if(!a[S[i]])
                    {
                        m++;
                        for(j=i;j<n;j++)
                            if(S[j]%S[i]==0)
                                b[j]=true;
                    }
                for(i=j=0;i<n;i++)
                    if(!b[i])
                    {
                        c[j++]=S[i];
                        printf("%d ",S[i]);
                        for(k=2;k<100;k++)
                            if(!a[k]&&S[i]%k==0)
                                a[k]=-1;
                    }
                n=j;
                if(!n)
                    return m;
                for(i=2,k=0;i<100;i++)
                    if(a[i]==-1)
                        p[k++]=i;
                for(i=0;i<n;i++)
                    for(d[i]=j=0;j<k;j++)
                        if(c[i]%p[j]==0)
                            d[i]|=(1<<j);
                memset(f,0,sizeof(f));
                empty=(1<<k);
                for(i=empty-1;i>=0;i--)
                    for(j=0;j<n;j++)
                        if((i&d[j])==0)
                            f[i]=max(f[i^d[j]]+1,f[i]);
                ret=0;
                for(i=0;i<empty;i++)
                    ret=max(f[i],ret);
                return ret+m;
            } 
            
     
    };  
  • 相关阅读:
    操作系统学习(一)、80x86保护模式内存管理
    Linux命令(十三) 建立目录 mkdir 删除目录 rmdir
    Linux命令(十二) 分割文件 split 合并文件 join
    Linux命令(十一) 显示文件类型 file
    linux下环境变量PS1设置
    Jenkins email-ext邮件通知模板
    building system busy, pls wait !!
    SCP 命令
    NDK Build 用法(NDK Build)
    android下m、mm、mmm编译命令的使用
  • 原文地址:https://www.cnblogs.com/xchaos/p/2574564.html
Copyright © 2020-2023  润新知