zoukankan      html  css  js  c++  java
  • 洛谷 题解 P3173 【[HAOI2009]巧克力】

    本蒟蒻又双叒叕被爆踩辣!

    又是一道经典的贪心题

    那么怎样切割该块巧克力,花费的代价最少呢?
    

    Solution:

    窝们考虑每个状态,有多少种选择方法?

    是不是可以选择横着切或者竖着切,就这两种方法吧;

    窝们再来考虑这两种方法的代价,

    首先,如果窝们准备横着切,那么此次处理的代价就是当前这次的代价*(已经竖着切的数量 + 1),因为已经竖着切出了这么多次,所以代价就是这个(那个+1的原因是巧克力本来就有一块好不好,切一次不就有两块辣。。。)

    ans += q.top() * s2;//那么当前的代价就是s2次乘单次代价 
    

    那么如果窝们现在准备竖着切,那么是不是同理就可以推出当前这次的代价*(已经横着切的数量 + 1),因为已经横着切出了这么多次,所以代价就是这个(那个+1的原因是巧克力本来就有一块好不好,切一次不就有两块辣。。。)

    ans += qq.top() * s1;//那么当前的代价就是s1次乘单次代价
    

    那么窝们已经知道了两种方案的代价辣,窝们接下来就是要找最优方案辣:

    窝们每次都比较两种方案,看那种更优窝们就选哪种方案

    因为窝们每次都选择当前最优,所以窝们也同时可以保证全局最优!

    Code:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define Rep(x, a, b) for(int x = a; x <= b; ++ x)
    
    priority_queue<int> q, qq;//优先队列可以维护序列单调性 
    //q表示横着切,qq表示竖着切
    
    int n, m, x, s1 = 1, s2 = 1, ans;
    //s1表示已经横着切了多少次辣 
    //s2表示已经竖着切了多少次辣 
    //ans就是答案辣
    
    int main(){
    scanf("%d%d", &n, &m);
    Rep(i, 1, n - 1){//因为切成n*m块,所以横着切n - 1次 
    scanf("%d", &x);//读入每次代价 
    q.push(x);//压入优先队列,维护其单调性 
    }
    Rep(i, 1, m - 1){//同理,竖着切m-1次 
    scanf("%d", &x);//读入每次代价
    qq.push(x);//压入优先队列,维护其单调性
    }
    while(! q.empty() && ! qq.empty()){//只要一个优先队列空了就要退出,因为如果有一个空了,那么它的top就会返回空,然后就会死循环。。 
    //找当前是竖着切更优还是横着切更优
    if(q.top() > qq.top()){//如果是横着切更优 
    ans += q.top() * s2;//那么当前的代价就是s2次乘单次代价 
    ++ s1;//记得更新s1的值,多了一份 
    q.pop();//已经切完的就要弹出 
    }
    else{
    ans += qq.top() * s1;//那么当前的代价就是s1次乘单次代价
    ++ s2;//记得更新s2的值,多了一份
    qq.pop();//已经切完的就要弹出
    }
    }
    //因为弹出来后只要一个方向是空,那么就只能去另一个方向辣,下面就是找哪一个不是空的 
    while(! q.empty()){//如果可以横着切,(好像也只能横着切 
    ans += q.top() * s2;// 那么当前的代价就是s2次乘单次代价 
    q.pop();//已经切完的就要弹出 
    ++ s1;//这里可加可不加辣,因为qq已经空了,s1就没用了 
    }
    while(! qq.empty()){//如果可以竖着切,(好像也只能竖着切 
    ans += qq.top() * s1;//那么当前的代价就是s1次乘单次代价
    qq.pop();//已经切完的就要弹出 
    ++ s2;//同上辣 
    }
    printf("%d", ans);//输出 
    return 0;
    }
    

    AC1

    修改一下:下面放一个对新人友好一点代码,思路差不多,不过注释较少

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n, m, ans, s1 = 1, s2 = 1;
    
    #define maxn 20010
    #define Rep(x, a, b) for(int x = a; x <= b; ++ x)
    
    struct node{
    int v, c;
    }e[maxn];
    
    bool cmp(node a, node b){
    return a.v > b.v;
    }
    
    int main(){
    scanf("%d%d", &n, &m);
    Rep(i, 1, n - 1){//因为切成n*m块,所以横着切n - 1次 
    scanf("%d", &e[i].v);
    e[i].c = 0;//把其标记为0 
    }
    Rep(i, n, n + m - 2){//同理,竖着切m-1次 
    scanf("%d", &e[i].v);
    e[i].c = 1;//把其标记为1 
    } 
    sort(e + 1, e + n + m - 1, cmp);
    Rep(i, 1, n + m - 2){
    if(e[i].c == 0){
    ans += e[i].v * s2;
    ++ s1;
    }
    else{
    ans += e[i].v * s1;
    ++ s2;
    }
    }
    printf("%d", ans);
    return 0;
    }
    

    AC2

    Ps:请看懂再抄

  • 相关阅读:
    HDOJ1556 Color the ball
    BUPT( 北邮)2 大数 AB
    DateTime.ToString()的用法
    判断DataTable中的空值(字段为数值型)?
    [转].NET平台下的Excel编程|C#操作Excel|Application和ApplicationClass的联系和区别
    [转]寻找SqlHelper
    C#认识/理解/运用 StreamReader,StreamWriter,StringReader,StringWriter[转]
    C# 应用微软的Visual Studio International Pack 类库提取汉字拼音首字母[转]
    [转]想靠写程序赚更多钱,写到两眼通红,写得比别人都又快又好好几倍,结果又能如何?
    DataRow复制一行到另一个DataTable[转]
  • 原文地址:https://www.cnblogs.com/Flash-plus/p/12028263.html
Copyright © 2011-2022 走看看