做了几道贪心基础例题,感觉代码不多,但好难想。。。下面附上几道题
①区间调度问题,每项工作分别在si,时间开始ti结束,不能重叠,问最多能参与多少项工作?(见《挑战》P40)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 10000
int n,s[maxn],t[maxn];
pair<int,int> itv[maxn];
void solve()
{
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;//t是最后所选工作的结束时间
for(int i=0;i<n;i++)
{
if(t<itv[i].second)//结束时间小于开始时间
{
ans++;
t=itv[i].first;
}
}
printf("%d\n",ans);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&s[i]);
for(int i=0;i<n;i++)
scanf("%d",&t[i]);
solve();
return 0;
}
②硬币问题,用有限张数的不同面值的纸币支付A原,问最少需要几张?
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
const int v[6]={1,5,10,50,100,500};
int c[6];//c[0]=c1,c[1]=c2....
int A;
void solve()
{
int ans=0;
for(int i=5;i>=0;i--)
{
int t=min(A/v[i],c[i]);//必须满足纸币的个数
A-=t*v[i];
ans+=t;
}
printf("%d\n",ans);
}
int main()
{
scanf("%d",&A);
for(int i=0;i<6;i++)
scanf("%d",&c[i]);
solve();
return 0;
}
③贪心算法——字典序最小问题,见《挑战》P43
问题主题:字典序最小
问题描述:
给定长度为N的字符串S,要构造一个长度为N字符串T。T是一个空串,反复执行下列任意操作:
l 从S的头部删除一个字符,加到T的尾部;
l 从S的尾部删除一个字符,加到T的尾部;
目标是要构造字典序尽可能小的字符串T。
限制条件:
1<=N<=2000
字符串都在大写字符
样例:
①输入
N=8
ADHCACBD
输出
②输入
N=5
ADCDA
输出
AADCD
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 2000
int n;
char s[maxn];
void solve()
{
int a=0,b=n-1;
while(a<=b)
{
bool left=false;
for(int i=0;a+i<=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--]);
}
putchar('\n');
}
int main()
{
scanf("%d",&n);
scanf("%s",s);
solve();
return 0;
}
④这个题是说给你n个点,然后让你标记其中尽可能少的点,使得n个点都处于被标记点左右不超过R的区间内,,求至少标记多少点?
思路:贪心~尽量充分利用区间,见《挑战》P45
输入:N=6
R=10
X={1,7,15,20,30,50}
输出:3
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000
int x[maxn];
int N,R;
void solve()
{ int i=0,ans=0;
sort(x,x+N);
while(i<N)
{
int s=x[i++];
//一直向右前进直到距离s的点大于R
while(i<N&&x[i]<=s+R) i++;
int p=x[i-1];//P是新加上的标记点的位置,实质将S更新为P
while(i<N&&x[i]<=p+R) i++;
ans++;
}
printf("%d\n",ans);
}
int main()
{
scanf("%d%d",&N,&R);
for(int i=0;i<N;i++)
scanf("%d",&x[i]);
solve();
return 0;
}
⑤.POJ3253 Fence repair见《挑战》P47
有一个农夫要把一个木板钜成几块给定长度的小木板,每次锯都要收取一定费用,这个费用就是当前锯的这个木版的长度
给定各个要求的小木板的长度,及小木板的个数n,求最小费用
提示:
以
①
3
5 8 5为例:
先从无限长的木板上锯下长度为 21 的木板,花费 21
再从长度为21的木板上锯下长度为5的木板,花费5
再从长度为16的木板上锯下长度为8的木板,花费8
总花费 = 21+5+8 =34
②
5
1 2 3 4 5
33
下面用的是优先队列,贪心可能超时
#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 2000
typedef long long ll;
int N;
int L[maxn],s[maxn];
void solve()
{
ll ans=0;
//声明一个从小到大取出数值的优先队列
priority_queue<int,vector<int>,greater<int> > que;
for(int i=0;i<N;i++)
{
que.push(L[i]);
}
//不断地进行木板合并
while(que.size()>1)
{
int l1,l2;
l1=que.top();
que.pop();
l2=que.top();
que.pop();
ans+=l1+l2;
que.push(l1+l2);
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&L[i]);
solve();
return 0;
}