- 一.贪心算法
贪心算法是一种求最优解的方法。它是按照某种最优策略,将复杂问题层层分解成子问题(每次一般只有一个),并由子问题的最优解“回溯”出整个问题的最优解。 从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。 如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。
利用贪心策略解题,需要解决两个问题: (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上面搜查前辈的解题方法,看懂了之后我就敲一遍提交,以上题目都是老师讲过我自己又做的,但我还是不能确定下次碰到类似的一定会做。不知道是不是因为智力因素,此课于我而言的确是个不小的挑战,不过我还是希望不断的经受锻炼,然后成长进步。