前言
又是没有写博客的半个月
没碰 C S D N CSDN CSDN的这些天过得可真充实~~
水一篇水题祭手~
题目
题目描述
(让人看不下去的英文题目) 请不想挑战英语水平的童鞋们直接往下翻
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.
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
中文版
题目描述
有
n
n
n个县会对
m
m
m个候选人投票,他们会按照一定顺序投票,除非前一个候选人退出选举,否则不会投下一个候选人的票,现在问你哪一个候选人能够获胜?请问至少让多少候选人退出,才能保证候选人
k
k
k获胜。
(如果说选票一样,那么编号小的就获胜)
输入
第一行输入三个数字
N
N
N(
1
≤
N
≤
100
1≤N≤100
1≤N≤100),
M
M
M(
1
≤
M
≤
15
1≤M≤15
1≤M≤15),
K
K
K(
1
≤
K
≤
M
1≤K≤M
1≤K≤M)
接下来
N
N
N行,每行输入
M
M
M个数字,表示第i个县投票的顺序。
输出
第一行输出如果所有候选人都不退出,最终的获胜者是谁。
第二行输出如果要使 K K K胜出,最少需要劝退多少名候选人。
解析
送分问
那么刚拿到这个题,就能够看出来,第一个问题实在简单,只需要在读入的时候处理一下就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];
}
在这里注意一下上面的标黑的句子,如果说票数是一样的话,那么编号小的会获胜。
送命问
关键就是第二个问题怎么搞?毕竟是 t 2 t2 t2,也不会特别难,因此我们就往简单的方向考虑。
因此我们思考一下就能够想出来一个方法,类似 I D D F S IDDFS IDDFS,只需要枚举一下最少会让多少个人退出,然后再 c h e c k check check一下差不多就行了。
c h e c k check check也不会太难,利用贪心思想,每次将当时的票数最高的人退出,然后统计新的票数,直到最高的票数是 k k k为止。
参考代码
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 ≤20分。。。
好吧接下来讲真正的题解:
其实思路确实很简单,暴力枚举所有的人,看到底需不需要让他退出、、、
其实说白了就是爆搜,而且时间十分充裕,完全可以跑完
#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;
}