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