第二周总结---贪心算法1

  • 一.贪心算法

贪心算法是一种求最优解的方法。它是按照某种最优策略,将复杂问题层层分解成子问题(每次一般只有一个),并由子问题的最优解“回溯”出整个问题的最优解。 从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。 如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。

利用贪心策略解题,需要解决两个问题: (1)该题是否适合于用贪心策略求解; (2)如何选择贪心标准,以得到问题的最优/较优解。

  • 二,题解
  • 1,最优装载问题
  • 有一批集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
    #include <iostream>
    #include <cstring>
    #include <string>
    #include<algorithm>
    using namespace std;
    struct load
    {
        int wight;
        int index;
    }box[1001];
    bool cmp(load x,load y)
    {
        return x.wight<y.wight;
    }
    int main()
    {
            int max,n,i,a[1001];
            while(cin>>max>>n)
            {
                memset(a,0,sizeof(a));
                memset(box,0,sizeof(box));
                 sort(box,box+n,cmp);
            for(i=1;i<=n;i++)
            {
                cin>>box[i].wight;
                box[i].index=i;
            }
            if(box[1].wight>max)
            {
                cout<<"no anwser!"<<endl;
                continue;
            }
            int s;
            for(i=1;i<=n;i++)
            {
            if(box[i].wight<=max)
            {
                a[box[i].index]=1;
                max=max-box[i].wight;
                 s=i;
            }
            }
            cout<<s-1<<endl;
            for(i=1;i<=n;i++)
            {
                if(a[box[i].index]) cout<<box[i].index<<" ";
                else continue;
            }
            cout<<endl;
    }
         return 0;
    }

     

  • 2,背包问题

给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。


#include <iostream>
#include <cstring>
#include <string>
#include<algorithm>
using namespace std;
struct load
{
    int wight;
    int value;
    double cc;
}bag[1001];
bool cmp(load x,load y)
{
    return x.cc>=y.cc;
}
int main()
{
        int n,i;
        double max;
        cin>>max>>n;
        for(i=1;i<=n;i++)
        {
            cin>>bag[i].wight>>bag[i].value;
            bag[i].cc=bag[i].value/bag[i].wight;
        }
        sort(bag+1,bag+n+1,cmp);
        double s=0;
        for(i=1;i<=n&&bag[i].wight<=max;i++)
        {
            max=max-bag[i].wight;
             s+=bag[i].value;
        }
        if(i<=n)
        {
            s+=1.0*bag[i].cc*max;
        }
        cout<<s<<endl;

     return 0;
}

3,面币找零

假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?

#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int money,ans=0;
    int count[7] = {3, 0, 2, 1, 2, 2, 3};
    int value[7] = {1, 2, 5, 10, 20, 50, 100};
    cin>>money;
    for(int i=6;i>=0;i--)
    {
        int c=min(money/value[i],count[i]);
        money-=c*value[i];
        if(c!=0)
        ans+=c;
    }
    if(money>0)
        cout<<"不能找零"<<endl;
    else cout<<ans;

    return 0;
}

 

4,区间调度
A。使用pair函数(不是很懂)
{pair 就是一个有两个函数的结构体,方便使用,头文件<utility>或者<map>,C++ STL  标准库提供了 pair 类模板,其专门用来将 2 个普通元素 first 和 second(可以是 C++ 基本数据类型、结构体、类自定的类型)创建成一个新元素<first, second>。通过其构成的元素格式不难看出,使用 pair 类模板来创建“键值对”形式的元素,再合适不过。
对pair里的元素进行排序,一般是对第一个first进行排序,second也跟着变化。

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=1000;
 int s[N],t[N];
pair<int, int> itv[N];
int main()
{
    int i,n,ans=0;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>s[i];
    }
    for(i=0;i<n;i++)
    {
        cin>>t[i];
    }
    //为了让结束时间早的工作排在前面,把T存入first,把S存入second
    for(i=0;i<n;i++)
    {
        itv[i].first=s[i];//pair默认对first升序,当first相同时对second升序;
        itv[i].second=t[i];
    }
    sort(itv,itv+n);
    int t=0;
    for(int i = 0; i < n; i ++) {
        if(t < itv[i].first) {
            ans ++;
            t = itv[i].second;
        }
    }
    cout<<ans<<endl;
    return 0;
}


B。结构体+sort
 

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
struct time
{
    int s;
    int t;
}ff[101];
bool cmp(time x,time y)
{
    if(x.s==y.t) return x.s<y.s;
    return x.t<y.t;
}
int main()
{
    int i,n,ans=1;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>ff[i].s;
    }
    for(i=0;i<n;i++)
    {
        cin>>ff[i].t;
    }
    sort(ff,ff+n,cmp);
    int t=ff[0].t;//把第一个结束的作为标志
    for(i=0;i<n;i++)
    {
        if(ff[i].s>t)
        {
            ans++;t=ff[i].t;//更换
        }
    }
    cout<<ans<<endl;
    return 0;
}

5.字典序最小问题

给定长度为N的字符串S,要构造一个长度为N字符串T。T是一个空串,反复执行下列任意操作: 从S的头部删除一个字符,加到T的尾部; 从S的尾部删除一个字符,加到T的尾部; 目标是要构造字典序尽可能小的字符串T。

#include<bits/stdc++.h>//万能头文件
#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;

int main()
{
   int i,n,m;
   char a[101];
   bool left=false;
   cin>>a;
   int len=strlen(a);
    m=0;n=len-1;
    while(m<=n)
{
   for(i=0;i<len;i++)
   {
       if (a[m+i]<a[n-i]) {left=true; break;}
       else if(a[i]>a[n]) {left=false;break;}
   }
        if(left) putchar(a[m++]);
        else putchar(a[n--]);

}

    return 0;
}


6,分发饼干问题,

你想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。注意:你可以假设胃口值为正。一个小朋友最多只能拥有一块饼干。 原则是大尺寸的饼干分给胃口大的孩子

这里用到了vector
A.(不用vector,我的想法)

#include<bits/stdc++.h>
using namespace std;

int main()
{
  int i,n,m;
  int a[100],b[100];
  cin>>n;
  for(i=0;i<n;i++)
    cin>>a[i];
  cin>>m;
  for(i=0;i<m;i++)
    cin>>b[i];
    sort(a,a+n);
    sort(b,b+n);
    i=0;int j=0,sum=0;
  while(i<n&&j<m)
  {
      if(a[i]<=b[j])
      {
          i++;
          sum++;
      }
      j++;
  }
  cout<<sum<<endl;
    return 0;
}

B。用vector(别人的)

#include<bits/stdc++.h>
using namespace std;

//贪心的思想:用尽量小的饼干去满足小需求的孩子,所以先进行排序
int findContentChildren(vector<int> &g, vector<int> &s)
{
    int childnum = 0;
    int cookienum = 0;
    sort(g.begin(), g.end()); //先将饼干 和 孩子所需大小都排序
    sort(s.begin(), s.end());
    while (childnum < g.size() && cookienum < s.size())
    { //当其中一个遍历完就结束
        if (g[childnum] <= s[cookienum])
        { //当用当前饼干可以满足当前孩子的需求,可以满足的孩子数量+1
            childnum++;
        }
        cookienum++; // 饼干只可以用一次,因为饼干如果小的话,就是无法满足被抛弃,满足的话就是被用了
    }
    return childnum;
}

int main()
{
    int child,cookie;
    vector<int>vecChild;
    vector<int>vecCookie;

    while(cin>>child)    //输入孩子的胃口
    {
        vecChild.push_back(child);
        char c = cin.get();
        if(c == '\n')
            break;
    }

    while(cin>>cookie)   //输入饼干的尺寸
    {
        vecCookie.push_back(cookie);
        char c = cin.get();
        if(c == '\n')
            break;
    }
    int result = findContentChildren(vecChild,vecCookie);
    cout<<result<<endl;
    return 0;
}


7,。小船过河问题
先将所有人过河所需的时间按照升序排序,我们考虑把单独过河所需要时间最多的两个旅行者送到对岸去,有两种方式:
最快的和次快的过河,然后最快的将船划回来;次慢的和最慢的过河,然后次快的将船划回来,所需时间为:t[0]+2*t[1]+t[n-1];
最快的和最慢的过河,然后最快的将船划回来,最快的和次慢的过河,然后最快的将船划回来,所需时间为:2*t[0]+t[n-2]+t[n-1]。

#include<bits/stdc++.h>
using namespace std;
bool cmp(int x,int y)
{
    return x<y;
}
int main()
{
    int i,num,t[1000],sum=0;
    cin>>num;
    for(i=0;i<num;i++)
        cin>>t[i];
        sort(t,t+num,cmp);
        while(num>3)
        {
            sum+=min(t[1]+t[0]+t[num-1]+t[1],t[num-1]+t[0]+t[num-2]+t[0]);
            num=num-2;
        }
        if(num==3) sum+=t[0]+t[1]+t[2];
        else if(num==2) sum+=t[1];
        else if(num==1) sum+=t[0];
        cout<<sum<<endl;
return 0;
}


8.正数区间
整数区间。请编程完成以下任务:   
       1. 读取闭区间的个数及它们的描述;   
       2.找到一个含元素个数最少的集合,使得对于每一个区间,都至少有一个整数属于该集合,输出该集合的元素个数。 
【输入】 
    首行包括区间的数目n,1<=n<=10000,接下来的n行,每行包括两个整数a,b,被一空格隔开,0<=a<=b<=10000,它们是某一个区间的开始值和结束值。
【输出】
    第一行集合元素的个数,对于每一个区间都至少有一个整数属于该区间,且集合所包含元素数目最少。
【样例输入】
    4
  3 6
  2 4
  0 2
  4 7
【样例输出】
  2

#include<bits/stdc++.h>
using namespace std;
struct A
{
    int begin;
    int end;
}ff[101];
bool cmp(A x, A y)
{
    return x.end<y.end;
}
int main()
{
    int i,n,sum=0;
    cin>>n;
    for(i=0;i<n;i++)
        cin>>ff[i].begin>>ff[i].end;
        sort(ff,ff+n,cmp);
        int x=-1;
        for(i=0;i<n;i++)
        {
            if(x>=ff[i].begin) continue;
            else
            {++sum;
            x=ff[i].end;}
        }
        cout<<sum<<endl;
return 0;
}

三,感想

上课的第二周了,有时候一些题目其实懂了却又敲不出来,很是苦恼。老师说在oj 上做题时不能参考别人的答案,一定要自己做,不然下次碰到还是不会。其实这对我又是一个挑战,因为我在做题的时候经常性的在csdn上面搜查前辈的解题方法,看懂了之后我就敲一遍提交,以上题目都是老师讲过我自己又做的,但我还是不能确定下次碰到类似的一定会做。不知道是不是因为智力因素,此课于我而言的确是个不小的挑战,不过我还是希望不断的经受锻炼,然后成长进步。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

季沐晴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值