1.区间调度问题
n项工作,每项工作都在s[i]时开始,在e[i]时结束,对于每项目工作都可以选择是否参加,如果选择了参与,那么自始至终都必须全程参与,参加工作时间段不能重叠,求最多能参加多少数量工作
样例:
n=5
s=1,2,4,6,8 e=3,5,7,9,10
result=3
思路:在可选择的工作中,每次都选取结束时间最早的工作
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
const int MAX_N=1000;
int n;
int k;
int s[MAX_N];//开始时间
int e[MAX_N];//结束时间
pair<int,int>it[MAX_N];
int solve()
{
//让时间结束早的工作排前面,e存在前面,s存在后面
for(int i=0;i<n;i++)
{
it[i].first=e[i];
it[i].second=s[i];
}
stable_sort(it,it+n);//按照字典序排列
int ans=0,t=0;
for(int i=0;i<n;i++)
{
if(t<it[i].second)//将上一个结束的时间与下一个开始的时间对比
{
ans++;
t=it[i].first;
}
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
{
cin>>s[i];
}
for(int i=0; i<n; i++)
{
cin>>e[i];
}
cout<<solve()<<endl;
}
return 0;
}
poj3617点击打开链接
题意:给定长度为n的字符串,构造一个长度为n的字符串,将s的头部和尾部进行比较,要求构建出的字符串尽可能小
题解:参考编程挑战,利用贪心思想,将首尾元素进行对比,将小的元素进行输出,如果元素相同,就接着往下比较
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
const int MAX_N=2005;
char s[MAX_N];
int main()
{
int n;
int cnt;
while(scanf("%d",&n)!=EOF)
{
memset(s,0,sizeof(s));
cnt=0;
for(int i=0; i<n; i++)
{
scanf(" %c",&s[i]);
}
int a=0;
int 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--]);
}
cnt++;
if(cnt==80)
{
printf("\n");
cnt=0;
}
}
printf("\n");
}
return 0;
}
poj3069点击打开链接
题解:从最左边开始考虑,寻找最远的点,将其标记,之后类推寻找最远点
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
const int MAX_N=2005;
int a[MAX_N];
int n,r;
int solve()
{
sort(a,a+n);
int i=0;
int ans=0;
while(i<n)
{
int s=a[i++];
//向右寻找距离包含在范围内的最远点
while(i<n&&a[i]<=s+r)
{
i++;
}
int p=a[i-1];
//一直向右寻找距离超出范围的点
while(i<n&&a[i]<=p+r)
{
i++;
}
ans++;
}
return ans;
}
int main()
{
while(scanf("%d%d",&r,&n))
{
if(r==-1&&n==-1)break;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
cout<<solve()<<endl;
}
return 0;
}
木板切块问题 poj3253点击打开链接
题意:例如长度为21的木板要切成5,8,8的三块木板。首先,长度21的木板切成13,8开销为21,再将长度为13的木板切成长度为5,8需要开销13,求最小开销
题解:贪心+哈夫曼树,设木板长度为L1,L2,L3...Ln,将其构建为哈夫曼树即最有二叉树,二叉树的根节点相加之和为最优解
首先介绍一个STL模板,priority_queue,引用一下前辈的博客http://www.cnblogs.com/flyoung2008/articles/2136485.html
接下来就是题目详解代码,采用了两种方法,推荐第二种,第一种超时了,思路犹存
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
const int MAX_N=20005;
int a[MAX_N];
int n;
int cmp(int u,int v)
{
return u>v;
}
LL solve1()
{
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
int k=n;
LL ans=0;
while(k>1)
{
stable_sort(a,a+k,cmp);
a[k-2]=a[k-1]+a[k-2];
ans+=a[k-2];
k--;
}
return ans;
}
LL solve2()
{
memset(a,0,sizeof(a));
LL ans=0;
int u,v;
priority_queue<int,vector<int>,greater<int> >que;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
que.push(a[i]);
}
while(que.size()>1)
{
u=que.top();
que.pop();
v=que.top();
que.pop();
ans+=(u+v);
que.push(u+v);
}
que.pop();
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
cout<<solve2()<<endl;
}
return 0;
}
关于优先队列的模板,这里再补充一道同样是运用贪心+优先队列的题目
题目链接如下https://vjudge.net/problem/POJ-2431
题意:给出一个数n,代表在两所城镇之间有n个加油站,接下来给出n行代表每个加油站距离目标城镇的距离以及所能提供的最大加油量,最后给出最开始汽车含有多少油,以及两所城镇的距离,假设卡车的燃油量是无限的,求卡车能否到达终点,如果可以,求出最少加油次数,否则输出-1
题解:不妨假设汽车所携带的油走过最长路径,将最长路径里的加油站所能加的油最大值加入到汽车中,不断维护这个优先队列,直至到达终点
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
const int MAX_N=10010;
typedef long long ll;
typedef long long LL;
int n,l,pp;
struct stu
{
int a;
int b;
} p[MAX_N];
bool cmp(stu u,stu v)
{
return u.a<v.a;
}
int solve()
{
priority_queue<int>q;
int ans=pp;//剩余油
int res=0;//加油次数
int s=0;//初始位置
int d;//需要跑多少
p[n].a=l;
p[n].b=0;
for(int i=0; i<=n; i++)
{
int d=p[i].a-s;
while(ans-d<0)//剩下的油不足以支撑下一个加油站
{
if(q.empty())
{
return -1;
}
ans+=q.top();
res++;//加1次油
q.pop();
}
ans-=d;
s=p[i].a;
q.push(p[i].b);
}
return res;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
{
scanf("%d%d",&p[i].a,&p[i].b);
}
scanf("%d%d",&l,&pp);
for(int i=0; i<n; i++)
{
p[i].a=l-p[i].a;
}
sort(p,p+n,cmp);
printf("%d\n",solve());
}
return 0;
}