比赛
(match.pas/c/cpp)
【问题描述】
jzyz要举行足球比赛了,根据学校安排,一共举行K场比赛,现在有N个班报名参加。
按照以往的历史战绩,这N支队伍都有自己的积分,并且保证这N支队伍的积分独一无二,不会出现相同。
为了合理安排球赛,采用主客场制,每个队伍最多参加2场比赛,最少参加0场比赛.
并且最多只能1次主场和最多只能1次客场。(主场的球队自己班可以组织拉拉队,客场则不行。)
并且某场比赛,积分高的为主场,积分低的为客场。
现在学校要求,这K场比赛中参加的队伍,要求每场比赛两只队伍的积分差越小越好。
现在学校把怎么安排比赛的任务交给了你,你要算出这K场比赛两只队伍积分差 的累加和最小是多少。
比如:有7支队伍,积分是:30,17,26,41,19,38,18。
有3场比赛,那么最好安排是2 vs 7,7 vs 5,6 vs 4。
此时等级差的总和等于(18-17)+(19-18)+(41-38)=5 达到最小。
【输入】
第一行两个正整数 N,K
接下来有n行,第i行表示第i+1 支队伍的积分。
【输出】
一个整数,表示等级差的总和。
【数据范围】
在 90%的数据中, 1<=n<=3000;
在100%的数据中, 1<=n<=100000;
保证所有输入数据中等级的值 小于 10^8, 1<=k<=n-1
【解题思路】
主客场其实就是一个队积分只能被减和减一次。
用sort按积分高低排序。
比较积分差存起来。
因为k<=n-1,不用考虑跨越比赛,所以对积分差排序,从小往大取k个。
【代码实现】
#include<bits/stdc++.h>
using namespace std;
int sum=0,n,k,i;
int a[100010];
int b[100010];
void cinn() {
cin>>n>>k;
for(i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
}
void work() {
for(i=1;i<n;i++)
b[i]=a[i+1]-a[i];
sort(b+1,b+n);
for(i=1;i<=k;i++)
sum+=b[i];
cout<<sum;
}
int main() {
cinn();
work();
return 0;
}
2.排队
(line.pas/c/cpp)
【问题描述】
某一迎接活动,N名学生站成一排。
编号为1…N。且队伍肯定按照编号的顺序依次排列,顺序不能再改变。
现在要把学生分成若干组,以便于统一管理。但是决策分组的小x发现有M对学生关系不好,
如果他们分到一组里,这个组就会出现一些状况,
所以小x决定只要关系不好的学生,肯定不能分到一组里。
现在小x想知道,最少分多少组,才能满足条件。
【输入】
第一行:两个整数,N和M。
接下来M行,每行两个整数Xi和Yi,表示第i组为编号为Xi和Yi的学生
【输出】
一个整数,表示小x最少要分的小组个数。
【数据范围】
20% N<=100 M<=50
40% M<=300
100% 2 <= N <= 1,000,000,00 M<=1000
【解题思路】
输入数据要注意数字小的在前,要判断一下。
首先考虑先后,设(x,y)两同学关系不好,用sort按y排序,只要下面x小于y的便不需要考虑了。
然后进行列举即可。
【代码实现】
#include<bits/stdc++.h>
using namespace std;
int x[100000000],y[100000000];
int sum=1;
int n,m,i,j,rightt=0;
struct psx{int x, y;}a[1010];
bool mycmp(psx k1,psx k2){ return (k1.y<k2.y || k1.y==k2.y && k1.x<k2.x); }
void cinn(){
cin>>n>>m;
for(i=1;i<=m;i++){
cin>>a[i].x>>a[i].y;
if(a[i].y<a[i].x)
swap(a[i].x,a[i].y);
}
}
void work(){
sort(a+1,a+1+m,mycmp);
for(i=1;i<=m;i++)
if(a[i].x>=rightt) sum++, rightt=a[i].y;
}
int main(){
cinn();
work();
cout<<sum;
return 0;
}
3.友好的握手
(misa.pas/c/cpp)
【问题描述】
hlgz有一个大型的庆典要举行。
在庆典会场中,一共有R*S个座位,也就是座位一共有R行,每行有S个座位。这次庆典整个sx地区的优秀学生要来参加。于是互相交流就成了这次庆典要首先做的事情,而交流的第一件事情就是握手。
我们认为相邻的方向是8个方向,具体如右图所示:
现在假设所有的人都已经进入会场,而小x作为神秘嘉宾最后进入会场。而小x最后要挑选出自己的座位,而他挑选座位的原则就是让所有可以握手的人的对数最多。
现在小x很迷茫,他想知道,他坐下后,不会再有人进来,那么最多有多少对不同的人可以握手。
当然,如果小x进来时,已经没有空位置,他就不能坐下。
【输入】
第一行两个整数 R和S 1 ≤ R, S ≤ 50
接下来R行,每行S个字符,每个字符代表某个位置的状态,字符只会是’.’ 或者’o’ ,’.'表示这个位置是空的,'o’表示这个位置已经坐了人。
这个状态是小x进来前的状态。
【输出】
一个整数,小x坐下后,最多能有多少对不同的人握手。
【数据范围】
有20% R=1 还有20% R=2 还有20% 小x进来之前就已经满了。
【题解思路】
判断小x未坐进去前的握手次数,然后判断空的位置最多可与几个人握手,在往上加即可。
【代码实现】
#include<bits/stdc++.h>
using namespace std;
int r,s;
char ch[10000][55];
int i,j,maxx=0;
int head=0,per=0;
void cinn(){
cin>>r>>s;
for(i=1;i<=r;i++)
for(j=1;j<=s;j++)
cin>>ch[i][j];
}
void work()
{
for(i=1;i<=r;i++)
for(j=1;j<=s;j++) {
if(ch[i][j]=='.') {
if(ch[i-1][j-1]= ='o') per++;
if(ch[i-1][j]= ='o') per++;
if(ch[i-1][j+1]= ='o') per++;
if(ch[i][j-1]= ='o') per++;
if(ch[i][j+1]= ='o') per++;
if(ch[i+1][j-1]= ='o') per++;
if(ch[i+1][j]= ='o') per++;
if(ch[i+1][j+1]= ='o') per++;
if(per>maxx)
maxx=per;per=0;
}
if(ch[i][j]= ='o') {
if(ch[i-1][j-1]= ='o') head++;
if(ch[i-1][j]= ='o') head++;
if(ch[i-1][j+1]= ='o') head++;
if(ch[i][j-1]= ='o') head++;
if(ch[i][j+1]= ='o') head++;
if(ch[i+1][j-1]= ='o') head++;
if(ch[i+1][j]= ='o') head++;
if(ch[i+1][j+1]= ='o') head++;
}
}
}
int main(){
cinn();
work();
cout<<head/2+maxx;
return 0;
}
4.岔路口
(ratf.pas/c/cpp)
【问题描述】
小x和他的小伙伴们一共N个人组成一队,在一个迷宫探险。
这个迷宫由道路和分岔口组成,如果碰到一个三岔路口,他们会分成两队,继续探险,以此类推,还会碰到路口,还会继续分成两队。
作为一名文艺青年,小x设置了他们如果要分成两队的条件:这两队的人数必须正好相差为K。如果不能相差为K,那么这队就在这个三岔口处就近考察,而不会继续探险。
现在小x想知道,最终会有多少支队伍。
【输入】
两个整数N和K。
【输出】
一个整数,最多有多少队。
【数据范围】
40% N<=100 K<=100
100% N<=1000000000 K<=1000
【题解思路】
简单递归即可
【代码实现】
#include<bits/stdc++.h>
using namespace std;
int n,k,l,t1,t2,sum=1;
void psx(int &l,int t1,int t2) {
if((l-k)%2==0) {
if(l<=k) return;
sum++;
t1=(l-k)/2;
t2=(l-k)/2+k;
psx(t2,0,0);
psx(t1,0,0);
}
}
int main() {
cin>>n>>k;
psx(n,0,0);
cout<<sum;
return 0;
}
5.飞来飞去
(putnik.pas/c/cpp)
【问题描述】
小x大学毕业后,进入了某个公司做了高层管理,他每年的任务就是检查这个公司在全国各地N个分公司的各种状况,每个公司都要检查一遍,且只能检查一遍,也就是说这N个地方只能也必须去一次。
当然,小x每年可以选择从任意一个城市开始,任意一个城市结束。
现在给出这N个公司所在地任意两个地点飞机票的价格,现在小x为了给公司省下交通费,需要设计一个程序,来计算一下如何花费最低能够完成任务(PS:这就是计算机算法理最经典的旅行商问题)
作为一名有过信息学竞赛经历的有志青年,小x给自己的路线又规定了一个约束条件:如果要访问编号为K的城市,那么编号比K小的所有城市或者在访问K之前访问,或者在访问K之后访问。这个条件也必须遵守。
比如:如果有3个城市:2 1 3和 3 1 2 的顺序都是合法的,但是 1 3 2的顺序就是非法的,因为比3小的1在3之前,2在3之后,和小x的要求冲突。
【输入】
第一行:一个整数N。
接下来N行,每行N个整数。第i行第j列的值a[i][j]表示第i个城市到第j个城市飞机票的价格。保证这N个整数在[0…1000]之间。
【输出】
一个整数,表示满足要求的最小花费。
【数据范围】
30% 数据保证N<=10
50% 数据保证 N<=20
100% 数据保证 N<=1500
【题解思路】
简单思考发现从1往两边推都是递增,从一开始,发现接下来的数只能在两边插入,那么进行递归,寻找最小值。之所以错,是因为从贪心方面思考,只保证了每次费用最少,而不是总体费用最少。
【代码实现】
#include<bits/stdc++.h>
using namespace std;
int n;
int fare[1505][1505];
int memo[1505][1505];
int i,j;
void cinn() {
cin>>n;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
cin>>memo[i][j];
}
int psx(int l,int r){
if(fare[l][r]) return fare[l][r];
int next=max(l,r)+1;
if(next==n) return 0;
return
fare[l][r]=min(memo[next][l]+psx(next,r),
memo[r][next]+psx(l,next));
}
int main(){
cinn();
cout<<psx(0,0);
return 0;
}