U116660 【第十届蓝桥杯省赛】评选最佳品牌 题解

· · 个人记录

该题题目较复杂,建议多读几遍题,搞懂题意和样例。

题目

题目链接:题目链接https://www.luogu.com.cn/problem/U116660

题面

n 个评委投票,在 m 个商品中评选一个最佳品牌。 评选采用多轮淘汰制,即:每轮投票,淘汰掉得票最少的候选品牌(得票并列最少的品牌一起淘汰)。

如此一轮轮淘汰下去,如果最后只剩下一个品牌当选,即告评选成功。

但如果在某轮投票中,当时未被淘汰的所有候选品牌(大于等于两个品牌)都并列得票最少,即告评选失 败。

如果评选成功就输出当选品牌号。否则输出最后一轮评选时唯一选票数的相反数。

在评选流程中,每个评委的态度都可用一个序列来表示;例如当 m=5 时,某评委的评选态度序列为:3、 5、1、2、4,则表示该评委:优先投 3 号,当 3 号被淘汰时投 5 号,当 3 和 5 都被淘汰时投 1,当 3、5、1 都 被淘汰时投 2,仅剩 4 号时才投 4 号品牌的票。

选票的序列中可以表示弃权,用 0 来表示,例如当 m=5 时,某评委的评选态度序列为:3、5、0,则表示 该评委:优先投 3 号,当 3 号被淘汰时投 5 号,其它情况下不投任何品牌的票。

请你编一个程序,模拟各轮投票的过程,得到评选结果。

输入格式

第一行:m(0<m<10,表示参加评选的品牌数)和 N(1<n<1000,表示参加投票的评委数),之间以空格分隔

接下来的 n 行:每行都是长度不超 m 的数字字符串,每个字符串表示一个评委的评选态度。

输出格式

评选结果。

解析:

现仅提供最基础的 暴力枚举解法 。

解法一(暴力枚举):

根据题目描述枚举每种情况。

该题需注意的坑较多,下面列举题目中的“坑”:

  1. 题目中输入为不含空格的连续数字,所以输入要特殊处理,比如采用字符串形式输入。
  2. 注意结果有两种状态,评选成功 和 评选失败 ,评选成功输出胜出品牌编号,评选失败输出最后一次最少得票数的相反数
  3. 注意0为弃权,0后数据不需要记录
  4. 每轮的最小得票数的产品可能有多个,淘汰产品时需要注意处理,投票轮数也不一定是n-1轮
  5. 注意之前被淘汰的产品是不会进入之后的评判及比较的

下附带解析AC代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
    int a/*评委人数*/,b/*产品数目*/,n/*临时记录字符串长度*/,num/**/,min_vote=0x3f3f3f3f/**/;
    char intention[1111][11];//记录评委投票意向(因输入为一串没有空格的数字,故采用char型进行输入) 
    bool vis[1111];//标记数组,标记下标为i的产品是否被淘汰,true表示被淘汰,false表示未被淘汰 
    int vote[11]={};//记录每个产品的票数 
    cin>>b>>a;
    num=b;
    for(int i=0;i<a;i++){
        cin>>intention[i];//因输入为一串没有空格的数字,故每一行以字符串的形式输入 
        n=strlen(intention[i]);
        for(int j=0;j<n;j++){//单字符变为数字
            intention[i][j]-='0';//为方便处理,这里将单字符变为数字(因字符本质是数字,所以可以继续将对应整数存入其中) 
        }
    }

    while(num>1){//投票轮数不固定,但知道剩余人数大于1是仍会继续投票 
        for(int i=1;i<=b;i++){//数组初始化,或可写成 memset(vote,0,sizeof(vote));
            vote[i]=0;
        }
        min_vote=0x3f3f3f3f;//初始化最小票数 

        //模拟评委投票的过程 
        for(int i=0;i<a;i++){//枚举每一位评委 
            for(int j=0;j<b;j++){//枚举每一件产品 
                if(intention[i][j]==0)break;//如果当前为0,表示该评委弃权,跳出当前评委的循环 
                if(vis[intention[i][j]]==false){//如果当前产品未被淘汰, intention[i][j]表示评委的投票的产品 
                    vote[intention[i][j]]++;//对应票数自增1 
                    break;  
                }
            }
        }

        //找到未被淘汰的商品中的最小票数 
        for(int i=1;i<=b;i++){
            if(vis[i]==true){//如果该产品被淘汰,跳过 
                continue;
            }
            min_vote=min(min_vote,vote[i]);//在未被淘汰的商品中占到最小票数 
        }

        //将得票数最少的产品淘汰。因得票最少的产品可能不唯一,故此处必须写循环 
        for(int i=1;i<=b;i++){
            if(vote[i]==min_vote){//如果当前产品的票数最少 
                vis[i]=true;//标记该产品为淘汰状态 
                num--;//产品数量较少1 
            }
        }
    }
    if(num==1){//如果仍有一件产品未被淘汰,即胜出 
        for(int i=1;i<=b;i++){//找到该见商品并输出 
            if(vis[i]==true){
                continue;
            }
            cout<<i;
        }
    }
    if(num==0){//如果所有产品都被淘汰,即为题目中 评选失败的情况 
        cout<<-min_vote;//输出最小得票数的相反数 
    }

    return 0;
}