zoukankan      html  css  js  c++  java
  • 【洛谷P1281 书的复制】二分+动态规划

    分析

    两个做法,一个DP,一个是二分。

    二分:也就是二分枚举每个人分到的东西。

    DP:区间DP F[I][J]表示前i本书分给j个人用的最短时间 由于每一次j的状态由比j小的状态得出,所以要先枚举j,然后枚举i,接着枚举上一次抄书的人是谁。

    AC代码(二分)

    #include <bits/stdc++.h>
    using namespace std;
    int m,k;
    int a[505];
    inline int read() {
        int w=0,x=0; char ch=0;
        while (!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while (isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return w?-x:x;
    }
    inline bool check(int x) {
        int cnt=0,tmp=0;
        for (int i=1;i<=m;i++) {
            if (tmp+a[i]>x) tmp=a[i],cnt++;
            else tmp+=a[i];
        }
        if (tmp>0) cnt++;
        if (cnt>k) return false;
        return true;
    }
    inline void print(int x) {
        int ans[505][2];
        int cnt=1,sum=0;
        ans[1][1]=m;
        for (int i=m;i>=1;i--) {
            if (sum+a[i]>x) {
                ans[cnt][0]=i+1;
                ans[++cnt][1]=i;
                sum=a[i];
            }
            else sum+=a[i];
        }
        ans[cnt][0]=1;
    	if (ans[1][0]>m)   for (int i=cnt;i>=2;i--) printf("%d %d
    ",ans[i][0],ans[i][1]);// 特判
        else for (int i=cnt;i>=1;i--) printf("%d %d
    ",ans[i][0],ans[i][1]);
    }
    int main(){
        int l=0,r=0,mid=0;
        m=read(),k=read();
        for (int i=1;i<=m;i++) a[i]=read(),r+=a[i];
        while (l<=r) {
            mid=(l+r)>>1;
            if (!check(mid)) l=mid+1;
            else r=mid-1; 
        }
        print(l);
        return 0;
    }
    

    AC代码(DP)

    #include <bits/stdc++.h>
    using namespace std;
    int f[501][501];
    int A[501],Sum[501];
    int N,K;
    void Print(int x,int Ans) {
        if(!x) return;
        for(int i=x;i>=0;i--) {
            if(Sum[x]-Sum[i-1]>Ans||!i) {
                Print(i, Ans);
                printf("%d %d
    ",i+1,x);
                break;
            }
        }
    }
    
    int main() {
        scanf("%d%d",&N,&K);
        for(int i=1;i<=N;i++) scanf("%d",&A[i]);
        for(int i=1;i<=K;i++)
            for(int j=1;j<=N; j++)
                f[i][j]=1e9;
        for(int i=1;i<=N;i++) Sum[i]=Sum[i-1]+A[i],f[1][i]=Sum[i];
        for(int i=2;i<=K;i++)
            for(int j=1;j<=N;j++) 
                for(int k=2;k<=j;k++)
                    f[i][j]=min(f[i][j],max(f[i-1][k-1],Sum[j]-Sum[k-1]));
        Print(N,f[K][N]);
        return 0;
    }
    
  • 相关阅读:
    一次zabbix的渗透
    Tips
    IPy
    文件读取漏洞路径收集
    argparse
    代码审计之配置
    ctf之加密
    内网渗透中的反弹Shell与端口转发
    利用zip(或者phar)协议进行本地文件包含
    104. 二叉树的最大深度
  • 原文地址:https://www.cnblogs.com/Dawn-Star/p/9830308.html
Copyright © 2011-2022 走看看