贪心法

暴力枚举 + 贪心法
  • 1.6.1 找出最大周长的三角形
/*可以用穷举找出最长,三重循环。*/
for (i = 0; i < a;++i) {
    for (j = i + 1; j < a; ++j) {
        for (k = j + 1; k < a; ++k) {
            len = b[i] + b[j] + b[k];
            ma = max(b[i], max(b[j], b[k]));
            ans = len - ma;
            if (ma < ans) { z = max(z, len); }
        }
    }
}
  • 1.6.2 Ants(POJ No.1852)
    Description
    An army of ants walk on a horizontal pole of length l cm, each with a constant speed of 1 cm/s. When a walking ant reaches an end of the pole, it immediatelly falls off it. When two ants meet they turn back and start walking in opposite directions. We know the original positions of ants on the pole, unfortunately, we do not know the directions in which the ants are walking. Your task is to compute the earliest and the latest possible times needed for all ants to fall off the pole.
/*2只蚂蚁相遇,把它看成相遇后还是沿原方向前行结果也是一样的*/
for (i = 0; i < n; ++i) {
        mint = max(mint, min(x[i], L - x[i]));
    }
for (i = 0; i < n; ++i) {
        maxt = max(maxt, max(x[i], L - x[i]));
    }
  • 1.6.3 抽签问题
    你的朋友提议玩一个游戏,将写有数字的n个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片上的数字后都将其放回口袋中,如果这四个数字的和为m,
    就是你赢,否则就是你的朋友赢,你挑战了好几次,结果一次也没有赢,于是撕破口袋,取出所有的纸片,检查自己是否有赢的可能性。
    请编写一个程序,判断当纸片上写的数字是K1,K2,K3,…,Kn 时,是否存在抽取四次和为m的情况,如果存在,输出Yes,若不存在,输出No。
/*如果n在合理范围内,可以直接四重循环穷举(循环:n^4)*/ 
bool f = false;
    for (a = 0; a < n;++a) {
        for (b =0; b < n;++b) {
            for (c = 0; c < n;++c) {
                for (d = 0; d < n;++d) {
                    if (k[a] + k[b] + k[c]+k[d]==m) {f = true;}
                }
             }
          }
       }
/*如果n过大,四重循环效率太慢,我们可以用二分搜索算法替换最内侧的循环*/
//循环:n^3logn ;排序:nlogn
bool binary_search(int *a,int n,int key) {
    int low, high,mid;
    bool f = false;
    low = 0;
    high = n;
    while (low <= high) {
        mid = (low + high) / 2;
        if (key < a[mid]) { high = mid - 1; }
        else if (key > a[mid]) { low = mid + 1; }
        else {f = true; break;}
    }
    return f;
}
<div class="divider"></div>
sort(k,k+n);
bool f = false;
    for (a = 0; a < n;++a) {
        for (b = 0; b < n;++b) {
            for (c =0; c < n;++c) {
if (binary_search(k, n, m - (k[a] + k[b] + k[c])))
                                                 { f = true;}
             }
          }
       }
/*同样道理,我们可以尝试用二分搜索来替换内侧两重循环;(循环:n^2logn;排序:n^2logn)*/
//先将内侧两重循环排好序
for (i = 0; i < n; ++i) {
        for (int j = 0; j < n;++j) {
            kk[i*n+j] = k[i] + k[j];
        } 
    }
    sort(kk,kk+n*n);
//再来搜索
bool f = false;
    for (a = 0; a < n;++a) {
        for (b = 0; b < n;++b) {
                if (binary_search(kk,kk+n*n, m - (k[a] + k[b]))) { f = true; }        
          }
       }    


贪心法
  • 硬币问题
    描述
    有1元、5元、10元、50元、100元、500元的硬币各C1、C5、C10、C50、C100 、C500 枚。现在要用这些硬币来支付A元,最少需要多少枚硬币?
    应用贪心法,我们可以尽可能多用面值大的硬币。
const int V[6]={1,5,10,50,100,500};
//省略输入C[i];
int ans;
for(int i=5;i>=0;i--){
int t=min(A/V[i],C[i]);
A-=t*V[i];
ans+=t;
}
cout<<ans<<endl;
  • 区间调度问题
    这里写图片描述
    这里写图片描述
    在可选的工作中每次选择结束最早的工作,代码:
    const int max_n = 100000;
    //输入
    int n, S[max_n], T[max_n];
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> S[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >>T[i];
    }
    //用于对工作排序的pair数组
    pair<int, int>itv[max_n];

    for (int i = 0; i<n; ++i) {
        itv[i].first = T[i];
        itv[i].second = S[i];
    }
    sort(itv,itv+n);
    int ans = 0, t = 0;
    for (int i = 0; i < n;++i) {
        if (t < itv[i].second) {
            ans++;
            t = itv[i].first;
        }
    }
  • 字典序最小问题

给定长度为N的字符串S,要构造一个长度为N的字符串T。最初,T是一个空串,随后反复进行下列任意操作:
从S的头部删除一个字符,加到T的尾部;从S的尾部删除一个字符,加到T的尾部。
目标是要构造字典序尽可能小的字符串T。
例如,当N=6,输入S=”ACDBCB”时,输出T=”ABCBCD”。
解决方法很简单,通过比较S和反转后的S’ ;哪个小用那个追加到T尾。

int a=0,b=n-1;
    while(a<=b){
            bool left=false;
        for(int i=0;i+a<=b;++i){
            if(S[a+i]<S[b-i]){
                left=true;
                break;
            }
            else if(S[a+i]>S[b-i]){
                left=false;
                break;
            }
        }
       if(left)putchar(S[a++]);
       else putchar(S[b--]);
  • Saruman’s Army
    这里写图片描述
    这道题有点类似于现实生活中的植物浇灌喷水头的部署,解题的思路:从最左边开始考虑,一直向右走,找出 距离为R以内的最远的点;由于更左的点没有覆盖意义,所以应该尽可能覆盖 更右的点。总之就是,找到一个点可以覆盖最大的区域S1,然后标记该点,再找出S1区域结束的最左点;不断重复循环就行。
int i=0,ans=0;
       while(i<N){
        int s=x[i++];   //假设的标记点,相对最左点;
        while(i<N&&x[i]<=s+R)i++;  
        int p=x[i-1];    //循环比较找出标记点p;
        while(i<N&&x[i]<=p+R)i++; //找出Si区域结束的最左点
        ans++;
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值