[COCI2017-2018 Contest4] Izbori

前言

又是沒有寫博客的半個月

沒碰CSDNCSDN的這些天過得可真充實~~

水一篇水題祭手~

題目

題目描述

(讓人看不下去的英文題目) 請不想挑戰英語水平的童鞋們直接往下翻

In a land with developed democracy far, far away, presidential elections for the football association are taking place. This land consists of N counties, and each county has its own football association. There are M presidential candidates labeled with 1, 2, … M. Each of the football associations will select exactly one candidate to cast their vote for. The winner of the election is the candidate with the most votes. If multiple candidates get the most amount of votes, the winner is the one with the smallest label.

During the election campaign, candidates visited the counties and tried to gain their sympathies. After having met all the candidates, each county’s football association determined the order in which they would cast their vote for each candidate.

For example, let’s assume that there are four candidates in the election and that one county’s order is 2, 1, 4, 3. This means that, unless they revoke their candidacy, the candidate with label 2 will get the county’s vote. If candidate 2 revokes their candidacy, and candidate 1 is still in the race, then they will get the vote, and so on.

Zdravko is a passionate football fan, and also a close friend of candidate with label K. He wants to know which candidate will win if neither of the candidates revokes their candidacy.

He also wants to know what is the minimal number of candidates he must persuade to revoke their candidacy in order for his friend, candidate K, to become the president of the football association.

Zdravko is currently dealing with other problems, so he is hoping that you will answer these questions.

輸入格式

The first line of input contains the numbers N (1 ≤ N ≤ 100), M (1 ≤ M ≤ 15) and K (1 ≤ K ≤ M) from the task.

Each of the following N lines contains the orders given by the counties’ football associations, i.e. a permutation of the first M natural numbers.

輸出格式

You must output the answers to the questions from the task, each in its own line.

輸入輸出樣例

樣例輸入1

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

樣例輸出1

3
3

樣例輸入2

4 1 1
1
1
1
1

樣例輸出2

1
0

樣例輸入3

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

樣例輸出3

2
3

中文版

題目描述
nn個縣會對mm個候選人投票,他們會按照一定順序投票,除非前一個候選人退出選舉,否則不會投下一個候選人的票,現在問你哪一個候選人能夠獲勝?請問至少讓多少候選人退出,才能保證候選人kk獲勝。
如果說選票一樣,那麼編號小的就獲勝
輸入
第一行輸入三個數字NN1N1001≤N≤100),MM1M151≤M≤15),KK1KM1≤K≤M

接下來NN行,每行輸入MM個數字,表示第i個縣投票的順序。
輸出
第一行輸出如果所有候選人都不退出,最終的獲勝者是誰。

第二行輸出如果要使KK勝出,最少需要勸退多少名候選人。

解析

送分問

那麼剛拿到這個題,就能夠看出來,第一個問題實在簡單,只需要在讀入的時候處理一下就ok了。

參考代碼

for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++)
            re (ord[i][j]);
        vod[ord[i][1]] ++;
        if (vod[ord[i][1]] > maxn || (vod[ord[i][1]] == maxn && ord[i][1] < pos))
            maxn = vod[ord[i][1]], pos = ord[i][1];
    }

在這裏注意一下上面的標黑的句子,如果說票數是一樣的話,那麼編號小的會獲勝。

送命問

關鍵就是第二個問題怎麼搞?畢竟是t2t2,也不會特別難,因此我們就往簡單的方向考慮。

因此我們思考一下就能夠想出來一個方法,類似IDDFSIDDFS,只需要枚舉一下最少會讓多少個人退出,然後再checkcheck一下差不多就行了。

checkcheck也不會太難,利用貪心思想,每次將當時的票數最高的人退出,然後統計新的票數,直到最高的票數是kk爲止。

參考代碼

void check (int id){
    vod[id] = 0; vis[id] = 1;
    for (int i = 1; i <= n; i++){
        ord[i][0] = 1;
        while (vod[ord[i][ord[i][0]]] == 0 && vis[ord[i][ord[i][0]]] && ord[i][0] < m)
            ord[i][0] ++;
        vod[ord[i][ord[i][0]]] ++;
        if (vod[ord[i][ord[i][0]]] > maxn)
            maxn = vod[ord[i][ord[i][0]]], pos = ord[i][ord[i][0]];
    }
}
int main (){
	for (int i = 1; i <= m; i++){
        maxn = 0;
        check (pos);
        if (pos == k){
            pr (i); putchar (10);
            return 0;
        }
    }
}

當然在這我加了一個小技巧,就是直接從上一次退出的那個人開始枚舉,如果他不是要退出或已退出的人,那麼就將他的選票加上。

這樣的話就不用從1枚舉到m來加上選票(其實意義不大,畢竟m最大就只是15,而且我也並不能保證這樣就是對的 手動滑稽

這片題解到此結束,大家可以離開了

真正的題解

哈哈哈哈哈哈嗝,不知道有沒有人真的信了上面的話,直接開碼然後交了啊?

不知道爲什麼,所有的貪心思路所形成的代碼分數都20\leq20分。。。

好吧接下來講真正的題解:

其實思路確實很簡單,暴力枚舉所有的人,看到底需不需要讓他退出、、、

其實說白了就是爆搜,而且時間十分充裕,完全可以跑完

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
#define reg register
#define LL long long
#define INF 0x3f3f3f3f

template<typename T>
void re (T &x){
    x = 0;
    int f = 1;
    char c = getchar ();
    while (c < '0' || c > '9'){
        if (c == '-') f = -1;
        c = getchar ();
    }
    while (c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + c - 48;
        c = getchar ();
    }
    x *= f;
}

template<typename T>
void pr (T x){
    if (x < 0){
        putchar ('-');
        x = ~x + 1;
    }
    if (x / 10) pr (x / 10);
    putchar (x % 10 + 48);
}

int n, m, k, ord[105][15], ans = INF, maxn, pos;
int vod[20];
bool vis[20];

void dfs (int indx, int sum){
    maxn = pos = 0;
    for (int i = 1; i <= m; i++)
        vod[i] = 0;
    for (int i = 1; i <= n; i++){
        int j = 1;
        while (vis[ord[i][j]] && j < m)
            j ++;
        vod[ord[i][j]] ++;
        if (vod[ord[i][j]] > maxn || (vod[ord[i][j]] == maxn && ord[i][j] < pos))
            maxn = vod[ord[i][j]], pos = ord[i][j];
    }
    if (pos == k){
        ans = min (ans, sum);
        return ;
    }
    for (int i = indx; i <= m; i++){
        if (!vis[i] && i != k){
            vis[i] = 1;
            dfs (i, sum + 1);
            vis[i] = 0;
        }
    }
}

int main (){
    //freopen ("izbori.in", "r", stdin);
    //freopen ("izbori.out", "w", stdout);
    re (n); re (m); re (k);
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++)
            re (ord[i][j]);
        vod[ord[i][1]] ++;
        if (vod[ord[i][1]] > maxn || (vod[ord[i][1]] == maxn && ord[i][1] < pos))
            maxn = vod[ord[i][1]], pos = ord[i][1];
    }
    pr (pos); putchar (10);
    if (pos == k){
        pr (0); putchar (10);
        return 0;
    }
    dfs (1, 0);
    pr (ans);
    putchar (10);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章