题意
给n个球m个篮子, 要求按照以下顺序将球放到篮子里, 最后输出按照以下规则放到篮子里的球的篮子编号
*1 优先放入球数少的篮子里
*2 优先靠近中间的框
*3 两个中间位置优先输出编号小的框
题解
用模拟和找规律都可以做出来
找规律发现输出的其实就是按题意顺序的 m 个篮子编号的循环节, 那么我们可以将这个循环节打表存起来, 遍历 n 个球输出循环节即可, 需要注意一下循环节输出的取模技巧
比如 11 个球 和 3 个篮子
循环节数组
值 | 无 | 2 | 1 | 3 |
---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 |
1 % 3 = 1 -----------------------------------------------------------------> 2
2 % 3 = 2 -----------------------------------------------------------------> 1
3 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
4 % 3 = 1 -----------------------------------------------------------------> 2
5 % 3 = 2 -----------------------------------------------------------------> 1
6 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
7 % 3 = 1 -----------------------------------------------------------------> 2
8 % 3 = 2 -----------------------------------------------------------------> 1
9 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
10 % 3 = 1 ---------------------------------------------------------------> 2
11 % 3 = 2 ---------------------------------------------------------------> 1
单纯的模拟用一个结构体封装每个球所在篮子的三个属性并做好初始化: 存球数量, 此篮子离中间篮子的距离( 当然需讨论奇数和偶数个篮子时 到中间位置的情况 ), 篮子编号. 然后模拟每次将一个球放到篮子里的过程, 找一个篮子, 球放进去( 篮子里的球数自增 ), 同时输出篮子编号
代码
规律大法 … 找规律找到循环节, 输出一串数一节
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
// const int MAXN = 1e2+10;
const int MAXN = 1e5+10;
int main ( ) { // freopen( "F:\\in\\.txt" , "r" , stdin );
int n, m;
sc( "%d%d", &n, &m );
int mid1, mid2;
int ans[MAXN];
bool flag = true;
if ( m%2 ) { // 奇数个篮筐求中间位置
mid1 = mid2 = (m+1)/2;
ans[1] = mid1;
// cout << ans[1] << " ";
mid1--, mid2++;
for ( int i = 2; i <= m; ++i ) {
if ( flag ) {
ans[i] = mid1--;
// cout << ans[i] << " ";
flag = false;
} else {
ans[i] = mid2++;
// cout << ans[i] << " ";
flag = true;
}
}
}
else { // 偶数个
mid1 = m/2;
mid2 = mid1+1;
for ( int i = 1; i <= m; ++i ) {
if ( flag ) {
ans[i] = mid1--;
flag = false;
// cout << ans[i] << " ";
} else {
ans[i] = mid2++;
flag = true;
// cout << ans[i] << " ";
}
}
}
// cout << endl;
for ( int i = 1; i <= n; ++i )
pf ( "%d\n", ans[i%m!=0 ? i%m : m] );
return 0 ;
}
模拟大法, 按题意重载小于号, 每次取出头模拟
可惜是c++学的不精, 不太明白重载友元函数和直接重载小于号的区别, 上面的是普通重载, 下面结尾处注释的是友元函数重载小于号, 不懂, 只知道普通重载慢了 … 这算是不求甚解?
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
const int MAXN = 1e5*3;
struct NODE {
int cnt, dis, id;
NODE ( ) { };
NODE ( int cnt, int dis, int id ) : cnt(cnt), dis(dis), id(id) { };
inline bool operator < ( const NODE& t ) const {
if ( cnt < t.cnt ) return true;
else if ( cnt == t.cnt ) {
if ( dis < t.dis ) return true;
else if ( dis == t.dis ) {
if ( id < t.id ) return true;
else return false;
} else return false;
} else return false;
}
};
int main ( ) {
int n, m;
set<NODE>s;
while ( ~sc ( "%d%d", &n, &m ) ) {
s.clear ( );
int mid1, mid2;
if ( m%2 ) { // 奇数个篮筐求中间位置
mid1 = mid2 = (m+1)/2;
}
else { // 偶数个
mid1 = m/2;
mid2 = mid1+1;
}
for ( int i = 1; i <= m; ++i ) { // 初始化每个篮筐
s.insert ( NODE( 0, min(abs(mid1-i), abs(mid2-i)), i ) );
}
for ( int i = 1; i <= n; ++i ) {
NODE tx = *s.begin ( );
s.erase ( s.begin ( ) );
tx.cnt++;
s.insert ( tx );
pf ( "%d\n", tx.id );
}
}
return 0;
}
// inline friend bool operator < ( const NODE &x, const NODE &y ) {
// if ( x.cnt < y.cnt )return true;
// else if ( x.cnt == y.cnt ) {
// if ( x.dis < y.dis )return true;
// else if ( x.dis == y.dis ) {
// if ( x.id < y.id )return true;
// else return false;
// }
// else return false;
// }
// else return false;
// }