[AtCoder Grand Contest 018]Sports Festival解题报告

传送门:https://agc018.contest.atcoder.jp/

日文题面:

問題文

高橋君は、スポーツ大会を開こうと考えています。 スポーツ大会に参加するのは、1 から N までの番号のついた N 人の人です。 また、大会で行うスポーツとして、1 から M までの番号のついた M 個のスポーツが候補に上がっています。 高橋君は、これらの中から 1 つ以上(全てでもよい)のスポーツを選んで、スポーツ大会で実施します。

高橋君は、人 i が、j 番目に好きなスポーツが Aij であることを知っています。 それぞれの人は、スポーツ大会で実施されるスポーツのうち、自分が最も好きなスポーツだけに参加し、他のスポーツには参加しません。

高橋君は、一つのスポーツにたくさんの人が集まり過ぎることを懸念しています。 そこで高橋君は、スポーツ大会で実施するスポーツをうまく選んで、最も多くの人が参加しているスポーツの参加人数を最小化したくなりました。 最も多くの人が参加しているスポーツの参加人数の最小値を求めてください。

制約

  • 1≤N≤300
  • 1≤M≤300
  • Ai1 , Ai2 , … , AiM は、1 から M の順列である。

入力

入力は以下の形式で標準入力から与えられる。

N M
A11 A12 … A1M
A21 A22 … A2M
:
AN1 AN2 … ANM

出力

最も多くの人が参加しているスポーツの参加人数の最小値を出力せよ。


入力例 1

4 5
5 1 3 4 2
2 5 3 1 4
2 3 1 4 5
2 5 4 3 1

出力例 1

2

スポーツ 1,3,4 を実施することにすると、人 1 はスポーツ 1 に、人 2 はスポーツ 3 に、 人 3 はスポーツ 3 に、人 4 はスポーツ 4 に参加します。 このとき、参加人数が最大のスポーツはスポーツ 3 で、その参加人数 2 人です。 また、参加人数が最大のスポーツの参加人数が 1 人になるような方法は存在しないので、この例の答えは 2 になります。


入力例 2

3 3
2 1 3
2 1 3
2 1 3

出力例 2

3

全員の好みが一致しているので、どうやっても一つのスポーツに 3 人集まってしまいます。 よってこの例の答えは 3 です。

英文题面:

Problem Statement

Takahashi is hosting an sports meet. There are N people who will participate. These people are conveniently numbered 1 through N. Also, there are M options of sports for this event. These sports are numbered 1 through M. Among these options, Takahashi will select one or more sports (possibly all) to be played in the event.

Takahashi knows that Person i's j-th favorite sport is Sport Aij. Each person will only participate in his/her most favorite sport among the ones that are actually played in the event, and will not participate in the other sports.

Takahashi is worried that one of the sports will attract too many people. Therefore, he would like to carefully select sports to be played so that the number of the participants in the sport with the largest number of participants is minimized. Find the minimum possible number of the participants in the sport with the largest number of participants.

Constraints

  • 1≤N≤300
  • 1≤M≤300
  • Ai1 , Ai2 , … , AiM is a permutation of the integers from 1 to M.

Input

Input is given from Standard Input in the following format:

N M
A11 A12 … A1M
A21 A22 … A2M
:
AN1 AN2 … ANM

Output

Print the minimum possible number of the participants in the sport with the largest number of participants.


Sample Input 1

Copy

4 5
5 1 3 4 2
2 5 3 1 4
2 3 1 4 5
2 5 4 3 1

Sample Output 1

Copy

2

Assume that Sports 1, 3 and 4 are selected to be played. In this case, Person 1 will participate in Sport 1, Person 2 in Sport 3, Person 3 in Sport 3 and Person 4 in Sport 4. Here, the sport with the largest number of participants is Sport 3, with two participants. There is no way to reduce the number of participants in the sport with the largest number of participants to 1. Therefore, the answer is 2.


Sample Input 2

Copy

3 3
2 1 3
2 1 3
2 1 3

Sample Output 2

Copy

3

Since all the people have the same taste in sports, there will be a sport with three participants, no matter what sports are selected. Therefore, the answer is 3.

大意:n个人,m种体育项目,A_{i,j}表示第i​​​​​​个人对第j项目喜爱程度排名;选出一些体育项目,每个人会参加这些体育项目中排名最小(最前)的体育项目;求出一种方案,保证此方案中参加人数最多的体育项目参加人数最少(相比于其它方案),并输出这个最小值。

法0:枚举子集,时间复杂度O(n*2^{m}),超时;

正解:贪心,先全选体育项目,每次删去人数最多的体育项目,得到不同的方案,记录这些方案中参加人数最多的体育项目的人数,取最小值;共能得到m种方案,每种方案需要先统计每种体育项目的参加人数,枚举n*m次次,并取最大值,枚举n次(虽然我代码用了排序,但其实是不需要的),故时间复杂度为O(mn+m^{2}n)

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
    struct newdata
    {
        int label,cnt;
    };
    int n,m;
    int a[301][301];
    newdata rankm[301];
    bool used[301];
bool cmp(newdata i,newdata j)
{
    return (i.cnt>j.cnt);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            if (j==1) rankm[a[i][j]].cnt++;
        }
    int now=0;
    for (int i=1;i<=m;i++)
        rankm[i].label=i;
    int ans=2147483647;
    while (now<m)
    {
        sort(rankm+1,rankm+m+1,cmp);
        ans=min(ans,rankm[1].cnt);
        used[rankm[1].label]=true;
        memset(rankm,0,sizeof(rankm));
        for (int i=1;i<=m;i++)
            rankm[i].label=i;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            	if (!used[a[i][j]])
            	{
					rankm[a[i][j]].cnt++;
					break;
				}
        now++;
    }
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/weixin_39872717/article/details/81117431