题目描述
小F和大F开了一所幼儿园,春天到了,幼儿园要举办一场运动会!
幼儿园里有N个小朋友,运动会里有M个项目可供选择,每个小朋友都对M个项目有一定的喜好程度。对于第i个小朋友,他第j喜欢的项目是aij。并且保证对于每个小朋友,他都不会有两个一样喜欢的项目。
幼儿园的园长小F和副园长大F对运动会的事情头疼不已,她们希望玩的人数最多的项目玩的人数最少,否则她们在最受欢迎的项目举行时会忙不过来。她们希望从M个项目中选出若干个项目在运动会中举行(可以全选,但不能一个也不选),每个小朋友会且仅会玩一个项目,并且他玩的项目一定是举行的项目中他最喜欢的。
很不幸,今天幼儿园停电了,电脑不能用,小F和大F决定将这个问题交给聪明的你,请你求出玩的人数最多的项目玩的人数的最小值。
输入
第1行两个整数N和M(1≤N,M≤300),表示小朋友的个数和备选运动项目的个数。
第2至N+1行,每行M 个整数。第i+1行的第j个整数表示aij,表示第i个小朋友第j喜欢的项目。保证ai1..aiM是1..M的一个排列。
输出
一个整数,表示玩的人数最多的项目玩的人数的最小值。
样例输入
4 5 5 1 3 4 2 2 5 3 1 4 2 3 1 4 5 2 5 4 3 1
样例输出
2
整体思路
以整体视角看题目,每次找到当前状态下被选择最多的项目,然后将该项目删除,改变状态,之后对该状态重复操作,求出每次操作的最小值;
如样例;初始状态下为(5,2,2,2)最大值为3,指示项目2,之后删除项目2;
改变后的状态为(5,5,3,5)最大值为3,指示项目5,之后删除项目5;
改变后状态为(1,3,3,4)最大值为2,指示项目3,删除项目3;
改变后状态为(1,1,1,4)最大值为3,指示项目1,之后删除项目1;
改变后状态为(4,4,4,4)最大值为4,指示项目4,之后删除项目4;
所有项目删除,最小值是2,空间复杂度为O(m);
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=310,inf=1e9;
int m,n;
int a[maxn][maxn];//表示第i个小朋友第j喜欢的项目
int cnt[maxn];//当前状态下项目i的参加人数
int now[maxn];//第i个小盆友项目选取的位置
//相对于每一个小朋友的喜爱项目序列
int mp[maxn];//用来标记不选的项目
int ans=inf;//储存最小的玩的人数最多的项目的人数
int pos;//指示当前玩的人数最多的项目
int mx;//用来记录每个状态下的最多人数
void input(){
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
scanf("%d",&a[i][j]);
}
}//输入
void init(){
for(int i=0;i<n;i++)
cnt[a[i][now[i]]]++;
//对每一个小盆友的第一喜爱项目进行计数
for(int i=1;i<m;i++){
mx=1; pos=-1;
for(int j=1;j<=m;j++)
if(!mp[j]&&mx<cnt[j]){
mx=cnt[j];
pos=j;
}
ans=min(ans,mx);
//找到当前状态下项目最大值
mp[pos]=1;
//标记当前最大的项目,煽情该项目
for(int j=0;j<n;j++){
if(mp[a[j][now[j]]]){
while(mp[a[j][now[j]]])
now[j]++;
//修改小盆友的状态
cnt[pos]--;
cnt[a[j][now[j]]]++;
//修改当前状态项目值
}
}
}
}
int main()
{
input();
init();
printf("%d",ans);
}
看了大佬的代码,但是大佬不注释就很烦。
改自:(2条消息) 2022大中小学生联合训练第十七场_yhy and lly的博客-优快云博客