L1-7 分寝室 - 第一套 2023年天梯赛真题 (pintia.cn)
学校新建了宿舍楼,共有 n 间寝室。等待分配的学生中,有女生 n0 位、男生 n1 位。所有待分配的学生都必须分到一间寝室。所有的寝室都要分出去,最后不能有寝室留空。
现请你写程序完成寝室的自动分配。分配规则如下:
- 男女生不能混住;
- 不允许单人住一间寝室;
- 对每种性别的学生,每间寝室入住的人数都必须相同;例如不能出现一部分寝室住 2 位女生,一部分寝室住 3 位女生的情况。但女生寝室都是 2 人一间,男生寝室都是 3 人一间,则是允许的;
- 在有多种分配方案满足前面三项要求的情况下,要求两种性别每间寝室入住的人数差最小。
输入格式:
输入在一行中给出 3 个正整数 n0、n1、n,分别对应女生人数、男生人数、寝室数。数字间以空格分隔,均不超过 105。
输出格式:
在一行中顺序输出女生和男生被分配的寝室数量,其间以 1 个空格分隔。行首尾不得有多余空格。
如果有解,题目保证解是唯一的。如果无解,则在一行中输出 No Solution
。
输入样例 1:
24 60 10
输出样例 1:
4 6
注意:输出的方案对应女生都是 24/4=6 人间、男生都是 60/6=10 人间,人数差为 4。满足前三项要求的分配方案还有两种,即女生 6 间(都是 4 人间)、男生 4 间(都是 15 人间);或女生 8 间(都是 3 人间)、男生 2 间(都是 30 人间)。但因为人数差都大于 4 而不被采用。
输入样例 2:
29 30 10
输出样例 2:
No Solution
感谢浙江警官职业学院楼满芳老师斧正数据!
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
初始代码:
#include<iostream>
using namespace std;
int n0,n1,n;
int x,y;
int a,b;
int chazhi;
int ans=-1;
int main(){
cin>>n0>>n1>>n;
chazhi=max(n0,n1);//差值不可能超过n0,或n1
for(int i=2;i<n0/2;i++){//从两间开始遍历
if(n0%i==0){
if(n1%(n-i)==0){
a=n0/i;//女生每间人数
b=n1/(n-i);//男生每间人数
if(a>1&&b>1){
int m_chazhi=abs(a-b);
if(m_chazhi<chazhi){
chazhi=m_chazhi;
ans=i;
}
}
}
}
}
if(ans==-1)
cout<<"No Solution"<<endl;
else
cout<<ans<<" "<<n-ans<<endl;
return 0;
}
优化判断结构(不影响结果):
#include <iostream>
using namespace std;
int n0, n1, n;
int chazhi;
int ans = -1;
int main() {
cin >> n0 >> n1 >> n;
chazhi = max(n0, n1); //差值不可能超过n0,或n1
for (int i = 2; i < n0 / 2; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
int m_chazhi = abs(n0 / i - n1 / (n - i));
if (m_chazhi < chazhi) {
chazhi = m_chazhi;
ans = i;
}
}
}
if (ans == -1)
cout << "No Solution" << endl;
else
cout << ans << " " << n - ans << endl;
return 0;
}
每日一题 分寝室(C++完成)_学校新建了宿舍楼,共有 n 间寝室。等待分配的学生中,有女生 n 0 位、男生 n 1 位-CSDN博客
第一次修改后:利用数组存所有结果,最后排序
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n0, n1, n;
int main() {
cin >> n0 >> n1 >> n;
vector<int> a;
for (int i = 2; i < n0 / 2; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
a.push_back( abs(n0 / i - n1 / (n - i)));
}
}
sort(a.begin(), a.end());
if (a.empty())
cout << "No Solution" << endl;
else
cout << a[0] << " " << n - a[0] << endl;
return 0;
}
第二次修改后:对比正确代码后,扩大遍历范围到n0(其实扩大到n0/2就行)
#include<iostream>
using namespace std;
int n0,n1,n;
int x,y;
int a,b;
int chazhi;
int ans=-1;
int main(){
cin>>n0>>n1>>n;
chazhi=max(n0,n1);//差值不可能超过n0,或n1
for(int i=2;i<n0;i++){//从两间开始遍历,到n0,而不是一半
if(n0%i==0){
if(n1%(n-i)==0){
a=n0/i;//女生每间人数
b=n1/(n-i);//男生每间人数
if(a>1&&b>1){
int m_chazhi=abs(a-b);
if(m_chazhi<chazhi){
chazhi=m_chazhi;
ans=i;
}
}
}
}
}
if(ans==-1)
cout<<"No Solution"<<endl;
else
cout<<ans<<" "<<n-ans<<endl;
return 0;
}
问题就在范围这。
优化判断结构:
#include <iostream>
using namespace std;
int n0, n1, n;
int chazhi;
int ans = -1;
int main() {
cin >> n0 >> n1 >> n;
chazhi = max(n0, n1); //差值不可能超过n0,或n1
for (int i = 2; i < n0; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
int m_chazhi = abs(n0 / i - n1 / (n - i));
if (m_chazhi < chazhi) {
chazhi = m_chazhi;
ans = i;
}
}
}
if (ans == -1)
cout << "No Solution" << endl;
else
cout << ans << " " << n - ans << endl;
return 0;
}
现在问题是为什么第一次修改没有用:
为什么用数组存放,排序后输出最小的思路会错,就算是改好了范围问题后:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n0, n1, n;
int main() {
cin >> n0 >> n1 >> n;
vector<int> a;
for (int i = 2; i < n0; i++) { //从两间开始遍历到n0
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
a.push_back( abs(n0 / i - n1 / (n - i)));
}
}
sort(a.begin(), a.end());
if (a.empty())
cout << "No Solution" << endl;
else
cout << a[0] << " " << n - a[0] << endl;//要输出的不是差值!
return 0;
}
重新捋一遍代码后,发现:
用来排序的根本不是要输出的,输出的排序关键字不是自己。
这种排序后,输出的不是关键字,而是与之相对应的其他属性,这种情况就要利用到结构体对多个属性的封装性,实现不同属性之间的捆绑。这也是结构体的妙处:一个变量包含多种捆绑在一起的信息。
此题要使用排序输出最小方案,就得将间数和人数差捆绑起来,pair、struct、map等都可以。
排序思路修改:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n0, n1, n;
typedef pair<int, int> node;
bool cmp(node i, node j) {
return i.second < j.second; //排序标准,小的在前
}
int main() {
cin >> n0 >> n1 >> n;
vector<node> a;
for (int i = 2; i < n0; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
{
node temp;
temp.second = abs(n0 / i - n1 / (n - i));
temp.first = i;
a.push_back( temp );
}
}
}
sort(a.begin(), a.end(), cmp);
if (a.empty())
cout << "No Solution" << endl;
else
cout << a[0].first << " " << n - a[0].first << endl;
return 0;
}
代码真的要步步有依据啊,跟数学题一样,步步不能错,步步要清晰,步步有依据。
看来,程序员的玩具鸭真有来头🤣🤣🤣
现在,还有一个问题,为什么不是遍历到 n0/2 就结束呢?
这得看看自己的思路草稿:
自己考虑的是 i∈[2,n0/2],但是代码写的却是i<n0/2,将n0/2排除了🤣😁😁😁
只用一个变量迭代保存最小值(同时保存对应的 i )的思路:
#include<iostream>
using namespace std;
int n0,n1,n;
int x,y;
int a,b;
int chazhi;
int ans=-1;
int main(){
cin>>n0>>n1>>n;
chazhi=max(n0,n1);//差值不可能超过n0,或n1
for(int i=2;i<=n0/2;i++){//从两间开始遍历到n0/2
if(n0%i==0){
if(n1%(n-i)==0){
a=n0/i;//女生每间人数
b=n1/(n-i);//男生每间人数
if(a>1&&b>1){
int m_chazhi=abs(a-b);
if(m_chazhi<chazhi){
chazhi=m_chazhi;
ans=i;
}
}
}
}
}
if(ans==-1)
cout<<"No Solution"<<endl;
else
cout<<ans<<" "<<n-ans<<endl;
return 0;
}
优化代码结构:
#include <iostream>
using namespace std;
int n0, n1, n;
int chazhi;
int ans = -1;
int main() {
cin >> n0 >> n1 >> n;
chazhi = max(n0, n1); //差值不可能超过n0,或n1
for (int i = 2; i <= n0 / 2; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
int m_chazhi = abs(n0 / i - n1 / (n - i));
if (m_chazhi < chazhi) {
chazhi = m_chazhi;
ans = i;
}
}
}
if (ans == -1)
cout << "No Solution" << endl;
else
cout << ans << " " << n - ans << endl;
return 0;
}
结构体数组排序思路:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n0, n1, n;
typedef pair<int, int> node;
bool cmp(node i, node j) {
return i.second < j.second; //排序标准,小的在前
}
int main() {
cin >> n0 >> n1 >> n;
vector<node> a;
for (int i = 2; i <= n0/2; i++) { //从两间开始遍历
if (n0 % i == 0 && n1 % (n - i) == 0 && n0 / i > 1 && n1 / (n - i) > 1) {
{
node temp;
temp.second = abs(n0 / i - n1 / (n - i));
temp.first = i;
a.push_back( temp );
}
}
}
sort(a.begin(), a.end(), cmp);
if (a.empty())
cout << "No Solution" << endl;
else
cout << a[0].first << " " << n - a[0].first << endl;
return 0;
}
顿时……看来自己的代码还不一定就符合自己的思路,和上面数组排序不用结构体控制输出犯了同样性质的错误:自己的代码并没有完美地表达自己的意思。
一开始几分钟就能AC的事……,只要我范围不写错,这题立马直接过,而不是自己傻乎乎照着别人的思路写,自己还没领悟清反而给自己找了另外的bug,最后发现自己的思路没错,只是一个范围漏了一点。
而这就恰恰说明了,当自己代码出现问题时,自己没有静下心来,第一时间仔细检查自己的每一步代码及其依据,而是浮躁的、不自信的,直接去看别人的代码。
心得:
当自己的代码有问题,先静下心来,不要觉得不耐烦,自己本来就是以一个不耐烦的心理状况写的,代码自然就不严谨,问题自然就多,这是自己造成的,现在就应该好好理理思路,想清楚每一步代码的逻辑和依据,先看自己代码实现是否符合自己思路,再考虑思路问题。
总结一下:
- 用来排序的根本不是要输出的
- 自己考虑的是 i∈[2,n0/2],但是代码写的却是i<n0/2,将n0/2排除了🤣😁😁😁
- 连续的 if 嵌套可以考虑放在一个 if 里,避免程序没必要的分支
- 这种排序后,输出的不是关键字,而是与之相对应的其他属性,这种情况就要利用到结构体对多个属性的封装性,实现不同属性之间的捆绑。
- 写代码的时候有多认真,debug的时候就用多轻松,你要反过来?对不起,bug只会只增不减
- 检查代码,先检查算法实现是否正确(一步一步说出依据),再考虑算法本身是否有问题(小黄鸭debug法哈哈哈哈)
我是小丑……