Xuzhou Summer Camp 1 贪心

本文集解析了多种经典算法问题,包括背包问题、活动安排、贪心算法、田忌赛马等,通过具体实例展示了不同算法的实现过程和关键思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

A - FatMouse' Trade

B - Schedule

C - Gene Assembly

D - Pass-Muraille

E - Tian Ji -- The Horse Racing

F - Wooden Sticks

G - Radar Installation

H - Copying Books


A - FatMouse' Trade

可拆分物品的背包

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int LG = 50;
const int MX = 1e6+5;
PII a[MX];
bool cmp(PII x,PII y){
    return x.FI*y.SE>y.FI*x.SE;
}
int main(){
    int n,m;while(cin>>m>>n){
        if(m==-1)break;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].FI,&a[i].SE);
        }
        sort(a+1,a+1+n,cmp);
        double ans=0;
        for(int i=1;i<=n;i++){
            if(m>=a[i].SE){
                m-=a[i].SE;
                ans=ans+(double)a[i].FI;
            }
            else {
                ans=ans+(double)a[i].FI*(double)m/(double)a[i].SE;
                m=0;
            }
            if(m==0)break;
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}

B - Schedule

题意:安排所有活动需要房间数量问题,并求出Σ(所有房间的使用时长)。

思路:首先对于所有的活动,先开始的优先,用map记录一个房间的开始时间和结束时间模拟。

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int LG = 50;
const int MX = 1e6+5;
PII a[MX];
bool cmp(PII x,PII y){
    return x.FI<y.FI;

}
multiset<PII>e;
int main(){
    int T;cin>>T;while(T--){
        int n;cin>>n;e.clear();
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].FI,&a[i].SE);
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++){
            auto id=e.lower_bound(MP(a[i].FI,INT_MAX));
            if(id==e.begin()){
                e.insert(MP(a[i].SE,a[i].FI));
            }
            else {
                id--;
                int zz=id->SE;
                e.erase(id);
                e.insert(MP(a[i].SE,zz));
            }
        }
        LL ans=0;
        for(auto i:e){
            ans=ans+(LL)(i.FI-i.SE);
        }
        cout<<e.size()<<' '<<ans<<'\n';
    }
    return 0;
}/*
5
5
1 3
12 15
2 5
4 8
3 6
3
1 3
4 6
2 5
*/

C - Gene Assembly

题意:一个房间最多能安排多少活动问题。

思路:贪心安排先结束的

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int LG = 50;
const int MX = 1e6+5;
map<int,vector<int> >ma;
map<PII ,int>zz;
vector<int>v;
int main(){
    int n;
    while(cin>>n){
        if(n==0)break;
        v.clear(),zz.clear(),ma.clear();
        for(int i=1;i<=n;i++){int l,r;scanf("%d%d",&l,&r);ma[r].push_back(l);zz[MP(l,r)]=i;}
        for(map<int,vector<int> >::iterator i=ma.begin();i!=ma.end();i++){
            sort(i->SE.begin(),i->SE.end());reverse(i->SE.begin(),i->SE.end());
        }
        int R=0;
        for(map<int,vector<int> >::iterator i=ma.begin();i!=ma.end();i++){
            if(i->SE[0]<R)continue;
            else R=i->FI,v.push_back(zz[MP(i->SE[0],i->FI)]);
        }
        printf("%d",v[0]);
        for(int i=1;i<(int)v.size();i++) printf(" %d",v[i]);
        puts("");
    }
    return 0;
}

D - Pass-Muraille

贪心删除对右边影响大的

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int LG = 50;
const int MX = 1e6+5;
int mp[105][105];
int R[105];
int main(){
    int T;cin>>T;while(T--){
        int n,k;cin>>n>>k;
        for(int i=0;i<=100;i++)for(int j=0;j<=100;j++)mp[i][j]=0;
        for(int i=1;i<=n;i++){
            int a,b,c,d;cin>>a>>b>>c>>d;
            if(a>c)swap(a,c);
            R[i]=c;
            for(int j=a;j<=c;j++){
                mp[j][b]=i;
            }
        }
        int ans=0;
        for(int i=0;i<=100;i++){
            int z=0;
            for(int j=0;j<=100;j++){
                if(mp[i][j]) z++;
            }
            while(z>k){
                ans++;z--;
                int mx=-1,u;
                for(int j=0;j<=100;j++){
                    if(mp[i][j]&&R[mp[i][j]]>mx)mx=R[mp[i][j]],u=j;
                }
                int jjj=R[mp[i][u]];
                for(int j=i;j<=jjj;j++)
                    mp[j][u]=0;
            }
        }
        cout<<ans<<'\n';
    }
    return 0;
}

E - Tian Ji -- The Horse Racing

题意:田忌赛马,赢了+100,输了-100,平局+0,求最多田忌的得分。

思路:能赢尽量赢,如果输,拿最坏的马输给对方最好的马

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define PII pair<int,int>
const int MX =510;

int main(){
    int n;while(cin>>n){
        if(!n)break;int a[1005],b[1005];
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        sort(a+1,a+1+n);sort(b+1,b+1+n);
        reverse(a+1,a+1+n);reverse(b+1,b+1+n);
        deque<int>w;deque<int>t;
        int ans=0;
        for(int i=1;i<=n;i++)t.push_back(a[i]);
        for(int i=1;i<=n;i++)w.push_back(b[i]);
        for(int i=1;i<=n;i++){
             if(t.front()>w.front()) ans++,t.pop_front(),w.pop_front();
             else if(t.front()<w.front()) ans--,t.pop_back(),w.pop_front();
             else if(t.back()>w.back()) ans++,t.pop_back(),w.pop_back();
             else if(t.back()<w.back()) ans--,t.pop_back(),w.pop_front();
             else ans-=(t.back()<w.front()),t.pop_back(),w.pop_front();
        }
        cout<<ans*200<<'\n';
    }
    return 0;
}

F - Wooden Sticks

题意:n个x*y的方块,如果x1<=x2&&y1<=y2,那么x1可以放在x2上面,求最少放几堆。

思路:按照x为第一关键字,y为第二关键字排序,然后一直找最长上升子序列。

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define PII pair<int,int>
const int MX =1e6+5;
pair<int,int>a[5005];
int vis[5005];
bool cmp(pair<int,int>x,pair<int,int>y){
    if(x.FI==y.FI)return x.SE<y.SE;
    return x.FI<y.FI;
}

int main(){
    int T;cin>>T;while(T--){
        int n;cin>>n;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].FI,&a[i].SE);
        }
        sort(a+1,a+1+n,cmp);int ans=0;
        for(int i=1;i<=n;i++){
            if(vis[i])continue;
            vis[i]=1;ans++;
            PII now=a[i];
            for(int j=i+1;j<=n;j++){
                if(!vis[j]&&a[j].FI>=now.FI&&a[j].SE>=now.SE) now=a[j],vis[j]=1;
            }
        }
        cout<<ans<<'\n';
    }
    return 0;
}

G - Radar Installation

题意:n个岛屿,至少在x轴放几个雷达,能使所有岛屿到最近的雷达距离<=R。

思路:以每个岛屿为中心点画半径为R的圆,那么可以在x轴上得到许多个区间。

然后从左到右遍历每一个区间,维护右端点的最小值,贪心的加雷达。

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define PII pair<int,int>
const int MX =1e4;
pair<double,double> a[MX];
int main(){
    int casen=0;
    int n,d;while(cin>>n>>d&&n){
        int tag=0;
        for(int i=1;i<=n;i++){
            double sx,sy;scanf("%lf%lf",&sx,&sy);
            a[i].FI=(double)sx-(double)sqrt(d*d-sy*sy);a[i].SE=(double)sx+(double)sqrt(d*d-sy*sy);
            if(sy>d) tag=1;
        }
        if(tag){printf("Case %d: -1\n",++casen);continue;}
        sort(a+1,a+1+n);
        double R=a[1].SE;int ans=1;
        for(int i=2;i<=n;i++){
            if(a[i].FI<=R) R=min(R,a[i].SE);
            else ans++,R=a[i].SE;
        }
        printf("Case %d: %d\n",++casen,ans);
    }
    return 0;
}

H - Copying Books

题意:将数组分成k块,使和最大的那一块的和最小。

思路:二分那个最小的和,因为输出的时候,要使越前面的和越小,那么从后往前分,并标记。

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define PII pair<int,int>
const int MX =510;
int a[MX],path[MX],ans[MX];int n,m;
bool check(LL x){
    memset(path,0,sizeof(path));
    int cnt=m;LL sum=0;
    for(int i=n;i>=1;i--){
        if(cnt==i+1) cnt--,path[i]=1;
        else if(sum+(LL)a[i]>x) sum=(LL)a[i],cnt--,path[i]=1;
        else sum+=(LL)a[i];
    }
    if(cnt<1)return 0;
    return 1;
}
int main(){
    int T;cin>>T;while(T--){
       cin>>n>>m;
       for(int i=1;i<=n;i++)scanf("%d",&a[i]);
       LL l=0,r=1e12;
       for(int i=1;i<=n;i++)l=max(l,(LL)a[i]);
       while(l<=r){
            LL mid=(l+r)/2;
            if(check(mid)){
                for(int i=1;i<=n;i++)ans[i]=path[i];
                r=mid-1;
            }
            else l=mid+1;
       }
       for(int i=1;i<=n;i++){
            cout<<a[i];
            if(i!=n)cout<<' ';
            if(ans[i]) cout<<"/ ";
       }
       puts("");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值