zoukankan      html  css  js  c++  java
  • codeforces#1290E2

    题目链接:

    https://codeforces.com/contest/1209/problem/E2

    题意:

    给出$n$行和$m$列

    每次操作循环挪动某列一次

    可以执行无数次这样的操作

    让每行最大值的累加和最大

    数据范围:

    $1leq n leq 12$

    $1leq m leq 20000$

    分析: 

    定义$dp[i][j]$,考虑前$i$列,选择状态为$j$的最大值

    $ans=dp[m][(1<<n)-1]$

    $dp[i][j]$可以由$dp[i-1][k]$转移,$k$是$j$的二进制子集

    $easy$难度还是比较好写的

    $hard$难度需要预处理,和保留最多$n$列

    easy代码:

    const int N=5;
    const int M=105;
    int n,m,B[M],A[N][M];
    int f[1<<N][M];
    int main( )
    {
        int i,j,k,t,z,r,u,G,T=read( );
        while(T--)
        {
            read(n);
            read(m);;
            for(i=1; i<=n; i++)
                for(j=1; j<=m; j++)
                    A[i][j]=read( );
            int S=(1<<n)-1;
            for(i=1; i<=m; i++)
                for(j=0; j<=S; j++)
                    f[j][i]=0;
            for(i=1; i<=m; i++)
            {
                for(j=0; j<=S; j++)
                {
                    for(k=j;; k=(k-1)&j)
                    {
                        u=0;
                        for(t=0; t<n; t++)
                        {
                            r=0;
                            for(z=1; z<=n; z++)
                            {
                                G=((z-1)+t)%n+1;
                                if(((1<<(G-1))&j)&&(!((1<<(G-1))&k)))
                                    r+=A[z][i];
                            }
                            u=max(u,r);
                        }
                        f[j][i]=max(f[j][i],f[k][i-1]+u);
                        if(!k) break;
                    }
                }
            }
            printf("%d
    ",f[S][n]);
        }
        return 0;
    }
    

      

    hard代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define pii pair<int,int>
    using namespace std;
    const int maxn=12+10;
    const int maxm=2007;
    int num[maxn][maxm];
    pii p[maxn*maxm];
    int lis[maxn][maxn],cnt;
    int dp[maxn][(1<<12)+10],f[maxn][(1<<12)+10];
    set<int>se;
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--){
            int n,m;
            scanf("%d %d",&n,&m);
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    scanf("%d",&num[i][j]);
                    p[(i-1)*m+j]=make_pair(num[i][j],j);
                }
            }
             sort(p+1,p+1+n*m);
             se.clear();
             for(int i=0;i<n*m;i++){
                 se.insert(p[n*m-i].second);
                 if(se.size()==n)break;//保留最多n列
             }
             int cnt=0;
             for(auto i:se){
                 cnt++;
                 for(int j=1;j<=n;j++)
                     lis[j][cnt]=num[j][i];
             }
             m=cnt;
    
            int len=(1<<n);
            memset(f,0,sizeof(f));
            for(int i=1;i<=m;i++)//预处理每列选择状态的最优解
                for(int choose=0;choose<len;choose++){
    
                    for(int j=1;j<=n;j++){
                         int res=0;
                        for(int k=1;k<=n;k++){
                            int g=(k-1+j)%n+1;
                            if((1<<(g-1))&choose)res+=lis[k][i];
                        }
                        f[i][choose]=max(res,f[i][choose]);
                    }
    
            }
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=m;i++){
                for(int choose=0;choose<len;choose++){
                    for(int shift=choose;;shift=((shift-1)&choose)){//枚举choose的子集
                        int v=choose-(shift&choose);
                        dp[i][choose]=max(dp[i][choose],dp[i-1][shift]+f[i][v]);
                        if(shift==0)break;
                    }
                }
            }
            printf("%d
    ",dp[m][len-1]);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Mybatis学习随笔3
    Mybatis学习随笔2
    Mybatis学习随笔
    Java校招面试-什么是线程安全/不安全
    装饰器2
    装饰器
    默认传参的陷阱
    处理日志文件
    第二天
    用户登录
  • 原文地址:https://www.cnblogs.com/carcar/p/11544541.html
Copyright © 2011-2022 走看看