zoukankan      html  css  js  c++  java
  • UVALive-4850 Installations

    题目大意:

    有若干任务, 每个任务有完成消耗的时间和截止的时间.

    如果完成某个任务的时刻是t, 截止时间是d, 那么罚时就是max( 0 , t-d ), 现在求罚时最大的任务和次大的任务的罚时和最少是多少.

    首先很快就可以想到一个贪心的方法: 按照时间限制d排序, 相同就按照安装时间s排序, 都从小到大, 扫一遍就可以了.

    然后就会发现过不了样例.

    那么我们来研究一下这个样例:

    6
    1 7
    4 7
    2 4
    2 15
    3 5
    3 8

    6个任务, 每一行前一个数是s, 表示完成消耗时间, 后一个数是d, 表示时间限制, 每个任务用Ji表示, 这个样例还有下面这个图来辅助解释:

    它按照贪心的方法放的话最大和次大应该是J6和J2, 结果是8, 但是正确答案是J2和J6, 答案是7.

    我们发现其实就是把J6和J2换了位置, 或者说, 是把J2放到了J6的后面.

    但是只交换最大和次大明显是错的, 而把后面的放到前面来只会让大的更大, 那么我们唯一可能的方法就是把前面的放到后面来.

    记一下罚时最大和次大的是哪两个任务, 然后去这两个靠后的一个的位置记为cd, 然后我们枚举cd前面的某一个移动到cd的后面, O( n )扫一遍计算答案, 更新答案, 不断移动. 再和完全不移动直接贪心的答案取min, 这样就可以得到答案了.

    为什么是对的? 首先cd之后的部分是不受移动的影响的, 我们从前面取出来一个放到了cd的后面, 而在cd前面的要么截止时间靠前, 要么处理时间短, 放到cd后面只会成为新的最大值, 而旧的最大和次大其中一个会变成次大值, 就有可能会使答案变小( 答案是最大和次大的和 ).

    为什么只移动一个? 因为把前面的放到cd后面, 结果变成最大, 如果再选一个绝对比原来的次大或者最大要大, 我们新增了两个更大的, 答案明显会更大, 所以只要选择一个交换.

    这样复杂度就是O( n )枚举移动, O( n )计算每一种答案, 总复杂度O( n^2 ).

    移动用链表实现.

    代码如下:

    //made by Crazy01
    #include<bits/stdc++.h>
    #define inf 1<<30
    #define ll long long
    #define db double
    #define c233 cout<<"233"<<endl
    #define mem(s) memset(s,0,sizeof(s))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int N=550;
    using namespace std;
    
    struct lll{
      int tim,lim;
      bool operator <(const lll &a)const{
        return lim==a.lim?tim<a.tim:lim<a.lim;
      }
    }job[N];
    int n,T,ans,cd,r[N];
    
    inline int gi(){
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
      return x*res;
    }
    
    void init(){
      n=gi(); r[0]=1;
      for(int i=1;i<=n;i++)
        job[i].tim=gi(),job[i].lim=gi(),r[i]=i+1;
      sort(job+1,job+1+n);
    }
    
    int calc(){
      int t=0,max1=0,max2=0;
      cd=0;
      for(int i=r[0];i<=n;i=r[i]){
        t+=job[i].tim;
        int tle=max(0,t-job[i].lim);
        if(tle>max1)max2=max1,max1=tle,cd=i;
        else if(tle>max2)max2=tle,cd=i;
      }
      return max1+max2;
    }
    
    void work(){
      if(!ans){printf("%d
    ",ans); return;}  
      for(int i=r[0],end=cd;i<end;i=r[i]){
        r[i-1]=r[i]; r[i]=r[end]; r[end]=i;
        ans=min(ans,calc());
        r[end]=r[i]; r[i]=r[i-1]; r[i-1]=i; 
      }
      printf("%d
    ",ans);
    }
    
    int main(){
      T=gi();
      while(T--){
        mem(job);
        init();
        ans=calc();
        work();
      }
      return 0;
    }
  • 相关阅读:
    动态生成 Excel 文件供浏览器下载的注意事项
    JavaEE 中无用技术之 JNDI
    CSDN 泄露用户密码给我们什么启示
    刚发布新的 web 单点登录系统,欢迎下载试用,欢迎提建议
    jQuery jqgrid 对含特殊字符 json 数据的 Java 处理方法
    一个 SQL 同时验证帐号是否存在、密码是否正确
    PostgreSQL 数据库在 Windows Server 2008 上安装注意事项
    快速点评 Spring Struts Hibernate
    Apache NIO 框架 Mina 使用中出现 too many open files 问题的解决办法
    解决 jQuery 版本升级过程中出现 toLowerCase 错误 更改 doctype
  • 原文地址:https://www.cnblogs.com/Crazy01/p/7683751.html
Copyright © 2011-2022 走看看