Codeforces Round #145 (Div. 1 C. Practice) 递归求解,归并思想 / 巧妙二进制分解

C. Practice

Little time is left before Berland annual football championship. Therefore the coach

of team "Losewille Rangers" decided to resume the practice, that were indefinitely

interrupted for uncertain reasons. Overall there are n players in "Losewille Rangers".

Each player on the team has a number — a unique integer from 1 to n. To prepare

for the championship, the coach Mr. Floppe decided to spend some number of practices.

Mr. Floppe spent some long nights of his holiday planning how to conduct the practices.

He came to a very complex practice system. Each practice consists of one game, all 

n players of the team take part in the game. The players are sorted into two teams in

some way. In this case, the teams may have different numbers of players, but each

team must have at least one player.

The coach wants to be sure that after the series of the practice sessions each pair of

players had at least one practice, when they played in different teams. As the players'

energy is limited, the coach wants to achieve the goal in the least number of practices.

Help him to schedule the practices.

Input

A single input line contains integer n (2 ≤ n ≤ 1000).

Output

In the first line print m — the minimum number of practices the coach will have to schedule.

Then print the descriptions of the practices in m lines.

In the i-th of those lines print fi — the number of players in the first team during the i-th

practice (1 ≤ fi < n), and fi numbers from 1 to n — the numbers of players in the first team.

The rest of the players will play in the second team during this practice. Separate

numbers on a line with spaces. Print the numbers of the players in any order. If there are

multiple optimal solutions, print any of them.

题意:

        N个人分成两队进行比赛,要求最终任意两个人均参与过一场比赛,且在不同队伍,

每只队伍至少一人。

思路:

      很容易想到一半一半的交换,但怎么实现,递归很容易就实现了,脑子短路,

比赛中不知为毛抛弃这个想法,换了一个每次取下标为偶数的数安排到一队。

结果成了较复杂的模拟。

      之前写模拟的时候,难确定的是比赛场数,实际上比赛场数就等于\left \lceil log_{2}N \right \rceil

巧妙方法将N个人转为二进制(要1~N,不能0~n-1,不然第一人和最后一人不能匹配),

不足K位的补全,每一位共N个0或者1,为0的一队,为1的一队即可。这个规律怎么考虑

的,不是很清楚。。。

二进制代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
const int M=4e4+100;
vector<int>vc[N];
int main() {

   freopen("input.txt","r",stdin);
   freopen("output.txt","w",stdout);
   int n,cnt=0;
   while(cin>>n) {
      cnt=0;
      for(int i=0; i<=n; i++)vc[i].clear();
      while( (1<<cnt)<n ) {
         cnt++;
      }
      for(int i=0; i<cnt; i++) {
         for(int j=1; j<=n; j++) {
            if(j>>i&1) {
               vc[i].push_back(j);
            }
         }
      }
      cout<<cnt<<endl;
      for(int i=0; i<cnt; i++) {
         cout<<vc[i].size()<<" ";
         for(int j=0; j<vc[i].size(); j++) {
            cout<<vc[i][j]<<" ";
         }
         cout<<endl;
      }
   }
   return 0;
}

递归代码实现:

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
const int M=4e4+100;
vector<int>vc[N];
int dfs(int l,int r,int step) {
   if(l==r)return 0;
   int mid=(l+r)/2;
   for(int i=l; i<=mid; i++) {
      vc[step].push_back(i);
   }
   return max(dfs(l,mid,step+1),dfs(mid+1,r,step+1))+1;
}
int main() {

   freopen("input.txt","r",stdin);
   freopen("output.txt","w",stdout);
   int n;
   while(cin>>n) {
      for(int i=0; i<=n; i++)vc[i].clear();
      int ans=dfs(1,n,1);
      cout<<ans<<endl;
      for(int i=1; i<=ans; i++) {
         cout<<vc[i].size()<<" ";
         for(int j=0; j<vc[i].size(); j++) {
            cout<<vc[i][j]<<" ";
         }
         cout<<endl;
      }
   }
   return 0;
}

大模拟代码实现:

(比赛次数计算可优化),但本身这个代码就很垃圾。。。

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
const int M=4e4+100;
int arr[N],tmp[N],vis[N];
int main() {

	freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
	int n;
	while(cin>>n) {
		memset(vis,0,sizeof(vis));
		memset(arr,0,sizeof(arr));
		memset(tmp,0,sizeof(tmp));
		int tmpn=n;
		int num=0,ww=0;
		if(n&1) {
			tmpn+=1;
		}
		for(int i=1; i<=tmpn; i++) {
			arr[i]=i;
		}
		while(1) {
			int kk=0;
			num++;
			for(int j=1; j<=tmpn; j+=2) {
				tmp[++kk]=arr[j];
				//cout<<arr[j]<<"..."<<endl;
				
				if(vis[arr[j+1]]==0) {
					ww++;
					vis[arr[j+1]]=1;
					//cout<<ww<<endl;
					if(ww==tmpn-1) {
						break;
					}
				}
				tmp[kk+tmpn/2]=arr[j+1];
			}
			if(ww==tmpn-1)break;
			for(int j=1; j<=tmpn; j++) {
				arr[j]=tmp[j];
			}
		}
		//cout<<".."<<endl;
		if(n%2==0) {
			cout<<num<<endl;
			for(int i=1; i<=n; i++) {
				arr[i]=i;
			}
			for(int i=1; i<=num; i++) {
				cout<<n/2<<" ";
				int kk=0;
				for(int j=1; j<=n; j+=2) {
					cout<<arr[j]<<" ";
					tmp[++kk]=arr[j];
					tmp[kk+n/2]=arr[j+1];
				}
				cout<<endl;
				for(int j=1; j<=n; j++) {
					arr[j]=tmp[j];
				}
			}
		} else {
			cout<<num<<endl;
			for(int i=1; i<=n; i++) {
				arr[i]=i;
			}
			for(int i=1; i<=num; i++) {
				cout<<n/2+1<<" ";
				int kk=0;
				for(int j=1; j<=n; j+=2) {
					cout<<arr[j]<<" ";
					tmp[++kk]=arr[j];
					tmp[kk+n/2+1]=arr[j+1];
				}
				cout<<endl;
				for(int j=1; j<=n; j++) {
					arr[j]=tmp[j];
				}
			}
		}


	}
	return 0;
}

THE END;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值