Week 2 贪心

1.P1007 独木桥

1. 本题核心:将两位士兵相遇后掉头---->两人交换身份到达原本对方的终点

2.min:所有人都朝离自己距离最近的端点走,反正所有人的速度都一样,也不存在相遇;然后在循环中两两比较谁花的时间最长。

3.max:所有人都朝离自己距离最远的端点走,遇到对方直接越过继续走,求其中的最长时间。

#include <bits/stdc++.h>
using namespace std;

int l,n,a[5010];

int main()
{
    int sum1=0,sum2=0;
    cin>>l>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        sum1 = max(min(l+1-a[i],a[i]),sum1);//所有士兵到自己离最近的端点中的最长距离
        sum2 = max(max(l+1-a[i],a[i]),sum2);//所有士兵到离自己最远的端点中的最长距离
    }
    cout<<sum1<<' '<<sum2;

    //sort(a,a+n);

    return 0;
}

2.P1223 排队接水

1.这题要求找到最短的等待时间,很明显的贪心加sort排序
2.因为本题要求输出明年时间最短的排队顺序,所以我设置了两个数组(动态数组a也可以直接写成普通数组,本来打算找到一个min,弹出一个min,所以用的vector,结果忘记了每弹出一个元素,角标i也会-1,那vector就没用了),a[ ]用来保存原来的输入顺序,t[ ]排序后用来与a[ ]进行比较,依次找到最短的接水时间。
3.最短的平均等待时间,我这里用的是,从最长的那段时间开始,依次n个人的等待时间的总和。

#include <bits/stdc++.h>
using namespace std;

int t[1010];
vector<int> a;

int main()
{
    int n;
    double ave,sum=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>t[i];
        a.push_back(t[i]);
    }

    sort(t,t+n);

    int temp = -1; // 将temp移到循环外面以避免重复初始化
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(t[i] == a[j]){
                if(temp == j+1)
                    continue;
                cout<<j+1;
                temp = j+1;
                if(i != n-1)
                    cout<<' ';
                break;
            }
        }
    }
    cout<<'\n';

    int x=n;//注意:不能改变n的值
    while(x--){
        for(int i=0;i<x;i++){
            sum += t[i];
        }
    }
    //cout<<sum<<endl;
    ave = sum/n;
    printf("%.2lf",ave);
    //cout<<fixed<<setprecision(2)<<ave;

    return 0;
}

3.P1803 凌乱的yyy / 线段覆盖

 一开始我用的是两个独立的数组,但是单用两个数组a[]和b[],两者之间没有逻辑关系,单对b[]排序时,a[]的顺序不会改变,所以要将a[]和b[]打包成一个结构体,并整体排序(排序具体规则见注释)。

然后就是简单判断了:如果下一场比赛的开始时间>上一场比赛的结束时间,那么yyy就能参加了,即sum++。

!!!结构体排序一定要自己定义cmp。

本题数组开得格外大(本蒟蒻卑微求解)

//结构体排序
#include <bits/stdc++.h>
using namespace std;

struct Time{
    int a;
    int b;
}oj[3000000];//数组开大点,虽然本蒟蒻也不知道为什么

//排序规则:先从小到大排结束时间,结束时间相等时,从小到大排开始时间
bool cmp(Time x,Time y)
{
    if(x.b==y.b) return x.a<y.a;
    return x.b<y.b;
}

int main()
{
    int n,sum=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>oj[i].a>>oj[i].b;
    }

    sort(oj,oj+n,cmp);

    int temp=-1;//放在循环里会重复赋初值为-1
    for(int i=0;i<n;i++){
        if(oj[i].a>=temp){
            sum++;
            temp = oj[i].b;
        }
    }
    cout<<sum;

    return 0;
}

4.P1031 [NOIP2002 提高组] 均分纸牌

 

虽然但是,我确实没有看到这个题哪里要用贪心(doge)。
最开始是想着算出平均数之后,先找到最大的那个数,再向左向右移,尽可能使得它和与它相邻的堆的纸牌数变成平均值,但是思考了半天,好像也没有很好的解决办法(大抵是水平太低,转化不成代码,卑微)。
所以……参考了一下题解,发现本题只需要求解最少移动次数,不用管到底是怎么移动的,反正只要纸牌数不等于就要移动
所以依次从左往右,不断将每一堆的纸牌数都变成平均数,如果a[i]==ave直接跳过,每移动一次,次数+1。

写了两种(其实原理一样),以下是先将每堆纸牌数都-ave,然后a[i]!=0时(即原来的纸牌数不等于ave)都要移动。

#include <bits/stdc++.h>
using namespace std;

int a[110];

int main()
{
    int n,sum=0,ans=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        sum += a[i];
    }
    int ave = sum/n;
    
    for(int i=0;i<n;i++)
        a[i] -= ave;//所有数据-ave,当a[i]==0时,移动完成
    
    for(int i=0;i<n-1;i++){
        if(a[i]==0)
            continue;//a[i]==0代表原来的纸牌数已经为平均数了,不用移动,直接跳过
        else{
            ans++;
            a[i+1] = a[i]+a[i+1];//不用管第i堆的纸牌数,直接将a[i]的值赋给a[i+1]就行
        }
    }
    cout<<ans;
    return 0;
}

第二种就是将a[i]直接与ave进行比较,不相等就移动。

#include <bits/stdc++.h>
using namespace std;

int a[110];

int main()
{
    int n,sum=0,ans=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        sum += a[i];
    }
    int ave = sum/n;

    for(int i=0;i<n-1;i++){

        if(a[i]==ave)
			continue; 
        else{
        	a[i+1] += a[i]-ave;
        	ans++;
    	}
	}
    cout<<ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棠梨下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值