2019.05.14校内考试

比赛

(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值