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;
}