题目链接

https://agc018.contest.atcoder.jp/tasks/agc018_b

题意简述

nn个人mm种运动,每个人给出了喜好每种运动的顺序,越靠前表示越喜欢。现在你需要选取一些运动,每个人会选取这些运动里他最喜欢的那个参加,求参加运动人数最多的运动的参加人数最少是多少。

题解

如果一个运动被kk个人选取了,那么删掉其他的运动,这个运动参加的人数不会变少。那么每次删掉参加人数最多的那些运动,取每次删的那种运动人数最小值即可。

代码

#include <cstdio>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=300;
const int inf=0x3f3f3f3f;

int n,m,a[maxn+4][maxn+4],in[maxn+4],mx[maxn+4],ans;

int main()
{
  n=read();
  m=read();
  for(int i=1; i<=n; ++i)
    {
      for(int j=1; j<=m; ++j)
        {
          a[i][j]=read();
        }
    }
  ans=n;
  int cnt=0;
  while(cnt<m)
    {
      for(int j=1; j<=m; ++j)
        {
          mx[j]=0;
        }
      for(int j=1; j<=n; ++j)
        {
          int nowi=-1;
          for(int k=1; k<=m; ++k)
            {
              if(!in[a[j][k]])
                {
                  nowi=a[j][k];
                  break;
                }
            }
          ++mx[nowi];
        }
      int now=-1;
      for(int j=1; j<=m; ++j)
        {
          if((!in[j])&&(mx[j]>now))
            {
              now=mx[j];
            }
        }
      ans=std::min(ans,now);
      for(int j=1; j<=m; ++j)
        {
          if((!in[j])&&(mx[j]==now))
            {
              in[j]=1;
              ++cnt;
            }
        }
    }
  printf("%d\n",ans);
  return 0;
}