贪心组题
Schedule
HDU 6180
每个任务有一个开始时间和结束时间,每台机器同一时刻只能做一个任务,求最少可以完成任务的机器数量。
经典的任务调度,将开始时间与结束时间同时排序,每开始/结束一个任务,当前任务数sum++/–,最少机器数即为过程中sum的最大值。
因为只要求总时间,不要求一一对应,所以只需求出即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e6+10;
typedef std::pair<int, int> pii;
pii a[2 * N];
int l[N], r[N];
int main(){
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
int s, e;
scanf("%d%d", &s, &e);
a[2 * i - 1] = pii(s, 1);
a[2 * i] = pii(e, -1);
}
sort(a + 1, a + 2 * n + 1);
memset(l, -1, sizeof(l));
memset(r, -1, sizeof(r));
int sum = 0, ans = 0;
for (int i = 1; i <= 2 * n; i++)
{
if (a[i].second == 1){
sum++;
if (l[sum] == -1) l[sum] = r[sum] = a[i].first;
ans = max(ans, sum);
}
else
{
r[sum] = a[i].first;
sum--;
}
}
ll time = 0;
for (int i = 1; i <= ans; i++) time += 1ll*(r[i] - l[i]);
printf("%d %lld\n", ans, time);
}
return 0;
}
Gene Assembly
ZOJ 1076
给个区间,求最多数量的不相交区间。
经典的区间调度,将右边界排序,顺序取即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e3+10;
typedef std::pair<int, int> pii;
struct node{
int l,r;
int id;
}a[N];
int n;
bool cmp(node a,node b){
if(a.r==b.r) return a.l>b.l;
else return a.r<b.r;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while(cin>>n && n)
{
for(int i=0;i<n;i++)
cin>>a[i].l>>a[i].r,a[i].id=i+1;
sort(a,a+n,cmp);
printf("%d",a[0].id);
int last=0;
for(int i=1;i<n;i++)
if (a[i].l > a[last].r){
printf(" %d", a[i].id);
last = i;
}
printf("\n");
}
return 0;
}
Pass-Muraille
POJ 1230
在一个网格上水平的有很多线段,对于每一列,从上到下最多只能穿过k个线段,求最少删去多少个线段。
很容易想到,某一列线段超过k个线段时,优先删除的肯定是线段右边界距当前列最远的,因为这样就可以使删除对后续答案影响最大。
upd:这题在poj上用cin总是wa,最后用了scanf才过。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e2+10;
typedef std::pair<int, int> pii;
int mtx[N][N];
int n,k;
struct node{
int x0,x1,y;
}a[N];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;
scanf("%d", &T);
while (T--)
{
int xn=0,yn=0,ans=0;
memset(mtx,0,sizeof mtx);
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) {
scanf("%d%d%d%d", &a[i].x0, &a[i].y, &a[i].x1, &a[i].y);
if (a[i].x0 > a[i].x1) swap(a[i].x0, a[i].x1);//填数据的坑
xn=max(xn,a[i].x1);
yn=max(yn,a[i].y);
for(int j=a[i].x0;j<=a[i].x1;j++) mtx[a[i].y][j]=a[i].x1;
}
for(int i=0;i<=xn;i++)
{
int d=0;
for(int j=0;j<=yn;j++)
if(mtx[j][i]) d++;
while(d>k)
{
int maxl=0,pos=0;
for(int j=0;j<=yn;j++)
if(mtx[j][i] > maxl)
{
maxl=mtx[j][i];
pos=j;
}
int posi=mtx[pos][i];
for(int j=i;j<=posi;j++)
mtx[pos][j]=0;
d--;
ans++;
}/*
for(int i=0;i<=m;i++)
{
for(int j=0;j<=m;j++) cout<<mtx[i][j]<<' ';cout<<endl;
}cout<<endl;*/
}
cout<<ans<<endl;
}
return 0;
}
Radar Installation
POJ 1328
求最少几个圆可以覆盖所有的点。
每个点的可覆盖圆圆心都在一个区间内,转化后问题变为数轴上最少取几个点可以被所有区间覆盖。
排序左边界后贪心。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e5+10;
typedef std::pair<int, int> pii;
struct node{
double l,r;
bool operator<(const node&rhs)const{
return l<rhs.l;
}
}a[N];
int n;
double d;
bool cmp(node a,node b){
return a.l<b.l;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int iCase=0;
while(cin>>n>>d &&n)
{
iCase++;
int x,y,flag=1;
for(int i=0;i<n;i++){
cin>>x>>y;
if(y>d) flag=0;//!如果在这里直接break则会影响读入,多组数据下会报错
if(flag) {
a[i].l = (double) x - sqrt(d * d - y * y);
a[i].r = (double) x + sqrt(d * d - y * y);
}
}
if(!flag) {
printf("Case %d: %d\n",iCase,-1);
continue;
}
sort(a,a+n);
int ans=1,last=0;
for(int i=1;i<n;i++) {
if (a[i].l > a[last].r) {
last = i;
ans++;
} else if(a[i].r < a[last].r) last=i;//一定要把last更新为r最小的那个线段
}
printf("Case %d: %d\n",iCase,ans);
}
return 0;
}
Wooden Sticks
HDU 1065
一个木棍有重量w和长度l,当一个木棍重量和长度都比另一个木棍小时,就可以不用加工。求最少的加工时长。
问题也就是求最少的w和l都满足递增的序列。
贪心,将w排序,然后递增的找l。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e4+10;
typedef std::pair<int, int> pii;
struct node{
int w,l;
}a[N];
int n;
double m;
bool cmp(node a,node b){
if(a.w==b.w) return a.l<b.l;
else return a.w<b.w;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].w >> a[i].l;
sort(a + 1, a + n + 1, cmp);
int vis[N] = {0}, ans = 0;
for (int i = 1; i <= n; i++) {
if (vis[i]) continue;
int maxl = a[i].l;
for (int j = i + 1; j <= n; j++) {
if (!vis[j] && maxl <= a[j].l) {
vis[j] = 1;
maxl = a[j].l;
}
}
ans++;
}
printf("%d\n", ans);
}
return 0;
}
Tian Ji – The Horse Racing
POJ 2287
田忌赛马
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define ll long long
using namespace std;
const int N = 1e3+10;
typedef std::pair<int, int> pii;
int n,a[N],b[N];
double d;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while(cin>>n &&n)
{
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
sort(a,a+n);//tian
sort(b,b+n);//king
int i,j,k,l,win=0,cnt=0;
i=j=0;//slow
k=l=n-1;//fast
while(cnt<n)
{
if(a[k]>b[l]){//田忌快?更快
++win;
k--;l--;
++cnt;
}
else if(a[k]<b[l]){//田忌快马比king快马慢,用最慢的马去输
--win;
i++;l--;
++cnt;
}
else{
if(a[i]>b[j]){//田忌慢?比king慢马快
++win;
i++;j++;
++cnt;
}else if(a[i]<b[l]){//尝试用慢马去赛king最快的马
--win;
i++;l--;
++cnt;
}else {
i++;l--;
++cnt;
}
}
}
cout<<200*win<<endl;
}
return 0;
}
浙公网安备 33010602011771号