[刷题之旅no36]P1309 [NOIP2011 普及组] 瑞士轮

暂时没什么好的思路,只能先试试看
1.读取,读取对数,R轮数,Q最终名次
2.循环2n次,读score
3.循环2n次,读power
4.根据score排序,将排序之后的编号存到rank数组中,rank可以直接和score合并成一个结构体
4.比较函数直接进行
好的思路:
第一次先希尔排序
因为每一次比赛都是两个人其中一个人加上一分,所以整个数组的整体顺序是没有发生太大变化的
可以先用希尔吧2n拆分成两个数组进行排序,第一个数组就是13579第二个数组就是2468 10,然后用一次归并直接排
先全都用希尔试一试
60分
TLE四个
看来确实要优化一下算法了。
不过倒是没超过1s,不过时间限制是500ms
看来随便蹭蹭就能进去了?
用我混合排序的方法试试
归并排序不需要递归版本
哈哈70分,有一个500ms正好蹭进去了
呜呜。也算是稍微有点提高了?
还应该怎么解决这个问题呢?
好像对于大数据有明显的提高,小一点的就差一点
要不全都改成merge?
试一试,好的,还是不行
看答案了
答案也用的是归并排序,但是和我理解的归并排序好像有点差别
哦!原来如此:
第一次排序之后,
之后再进行比赛
赛后把赢的人归为一队,输的人归为一队
发现赢得人的相对位置不发生改变,所以为有序队
同理输的人也是有序队,
所以我们得到了两个有序队列
只需要把这两个队列再进行归并排序不就好了吗!!!
天啊!
我竟然没有想到,思考的时间太少了啊!!!
我本来就应该直到不应该这样直接排序的啊!
以此为教训,以后思考问题必须在一个小时以上才行。
更新思路
1.数据结构
新设置一个winner和loser数组,用于按照顺序记录winner和loser的number值
2.函数compare,在每次比较之后,进行winner和lose的记录
3.归并排序函数,每次归并按照Winner和loser里面的下标进行遍历比较
7个RE赶紧看看是咋回事
OK是我的希尔排序判断出现了运算顺序上的问题,也就是判断的时候出现了错误,已经改正

#include<stdio.h>
//时刻注意这道题数组总长度为2*n 
typedef struct
{
	int score,number,power;
}Rank;
Rank rank[200005],tmp[200005];
int win[100005],lose[100005];
int n,r,q;
void scan()
{
	scanf("%d %d %d",&n,&r,&q);
	for(int i=1;i<=2*n;i++)
	{
		scanf("%d",&rank[i].score);
		rank[i].number=i;
	}
	for(int i=1;i<=2*n;i++)
	{
		scanf("%d",&rank[i].power);
	}
}
void compare()
{
	for(int i=1;i<=n;i++)//n对比赛
	{
		if(rank[2*i-1].power>rank[2*i].power)//记录winer和loser 
		{
			rank[2*i-1].score++;
			win[i]=2*i-1;
			lose[i]=2*i;
		}
		else if(rank[2*i-1].power<rank[2*i].power)
		{
			rank[2*i].score++;
			win[i]=2*i;
			lose[i]=2*i-1;
		}
		else
		{
			win[i]=2*i-1;
			lose[i]=2*i;
		}
	}
}
void sort()//归并排序,下标存在win和lose数组里面 
{
	int pa=1,pb=1,pt=1;
	while(pa<=n&&pb<=n)
	{
		if(rank[win[pa]].score>rank[lose[pb]].score)
		{
			tmp[pt++]=rank[win[pa++]];
		}
		else if(rank[win[pa]].score<rank[lose[pb]].score)
		{
			tmp[pt++]=rank[lose[pb++]];
		}
		else if(rank[win[pa]].score==rank[lose[pb]].score)
		{
			if(rank[win[pa]].number<rank[lose[pb]].number)
			{
				tmp[pt++]=rank[win[pa++]];
			}
			else
			{
				tmp[pt++]=rank[lose[pb++]];
			}
		}
	}
	while(pa<=n)
	{
		tmp[pt++]=rank[win[pa++]];
	}
	while(pb<=n)
	{
		tmp[pt++]=rank[lose[pb++]];
	}
	pt=1;
	for(int i=1;i<=2*n;i++)
	{
		rank[i]=tmp[pt++];
	}
}
void print()
{
	printf("number:");
	for(int i=1;i<=2*n;i++)
	{
		printf("%d ",rank[i].number);
	}
	printf("\n");
	printf("score :");
	for(int i=1;i<=2*n;i++)
	{
		printf("%d ",rank[i].score);
	}
	printf("\n");
	printf("power :");
	for(int i=1;i<=2*n;i++)
	{
		printf("%d ",rank[i].power);
	}
	printf("\n");
}
void shellsort()
{
	Rank tmpa;
	for(int gap=n;gap>0;gap=gap/2)
	{
		for(int i=gap+1;i<=2*n;i++)
		{
			for(int j=i;(j-gap>0)&&((rank[j].score>rank[j-gap].score)||(rank[j].score==rank[j-gap].score&&rank[j].number<rank[j-gap].number));j=j-gap)
			{
				tmpa=rank[j];
				rank[j]=rank[j-gap];
				rank[j-gap]=tmpa;
			}
		}
	}
}
int main()
{
	scan();
	shellsort();
	for(int i=1;i<=r;i++)
	{
		compare();
		sort();
//		shellsort();
	}
	printf("%d",rank[q].number);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值