ABC三人参加类似美国大选的竞选,一共N个州,每个州有不同数量的最终选票,赢得一个州的初选即获得该州的全部选票
给出每个州的最终选票数和预期初选结果
现在已知C每个州都是最少的,最终预期结果当然也是落选的,他需要到每个州去动员选民修改选票
限制只能动员该州得票最多的人,转投他自己,或者另一个人(得票第2多的人) (这个限制其实是将题目简化)
问 所有的州加起来,最少需要动员多少人,才能让C最终获胜
输入:
用例数T
N
N个州的最终选票数
A的预期初选结果
B的预期初选结果
C的预期初选结果
输出:最少动员人数
3
7
55 80 5 35 80 70 80
65 60 75 80 50 50 80
60 80 70 95 95 95 45
25 50 35 45 10 15 35
5
75 20 35 10 40
90 95 90 50 40
95 70 95 45 55
35 60 20 35 10
9
30 65 25 40 85 45 75 45 60
80 70 15 70 20 40 45 55 55
40 85 95 40 95 35 65 65 60
30 40 10 20 15 15 10 50 20
#1 47
#2 59
#3 73
Votes_wangyanli.java :
import java.io.FileInputStream;
import java.util.Scanner;
public class Votes {
static int[] cityValues;
static int[][] votes;
static int[] candidatesResults;
static int N;
static int step;
static int moveNum;
static int minMoveNum;
public static void main(String args[]) throws Exception {
// Scanner sc = new Scanner(System.in);
Scanner sc = new Scanner(new FileInputStream("votes.txt"));
int T = sc.nextInt();
for(int tc = 0; tc < T; tc++) {
N = sc.nextInt();
cityValues = new int[N];
candidatesResults = new int[3];
for (int i = 0; i < N; i++) {
cityValues[i] = sc.nextInt();
}
votes = new int[N][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < N; j++) {
votes[j][i] = sc.nextInt();
}
}
for (int i = 0; i < N; i++) {
if (votes[i][0] > votes[i][1]) candidatesResults[0]+=cityValues[i];
else candidatesResults[1]+=cityValues[i];
}
minMoveNum = 99999999;
for (int i = 0; i < 3; i++) {
step = 0;
moveNum = 0;
dfs(i);
}
System.out.println(minMoveNum);
}
sc.close();
}
static void dfs(int stateChoice) {
if(moveNum >= minMoveNum) return;
// 这里就可以在任何一步都去判断,是否已经完成动员工作,已完成的情况下,后续的州自然就不需要了
if (candidatesResults[2] > candidatesResults[0] && candidatesResults[2] > candidatesResults[1]) {
minMoveNum = moveNum;
return;
}
// 这种写法,在所有州都完成(不符合上面拉票成功的情形)时,也要返回
if (step == N) {
return;
}
//the first to the second
if (stateChoice == 1) {
moveNum += (Math.abs(votes[step][1]-votes[step][0])/2+1);
if (votes[step][1]>votes[step][0]) {
candidatesResults[0]+=cityValues[step];
candidatesResults[1]-=cityValues[step];
}
else {
candidatesResults[1]+=cityValues[step];
candidatesResults[0]-=cityValues[step];
}
}
//the first to shark
else if (stateChoice == 2) {
//shark become the first
if (votes[step][1]>votes[step][0]) {
int move = Math.abs(votes[step][1]-votes[step][2])/2+1;
if (votes[step][2]+move > votes[step][0]) moveNum += move;
else moveNum += (move + votes[step][0]-(votes[step][2]+move)+1);
candidatesResults[1]-=cityValues[step];
}
else {
int move = Math.abs(votes[step][0]-votes[step][2])/2+1;
if (votes[step][2]+move > votes[step][1]) moveNum += move;
else moveNum += (move + votes[step][1]-(votes[step][2]+move)+1);
candidatesResults[0]-=cityValues[step];
}
candidatesResults[2]+=cityValues[step];
}
step++;
for (int i = 0; i < 3; i++) {
dfs(i);
}
step--;
if (stateChoice == 1) {
moveNum -= (Math.abs(votes[step][1]-votes[step][0])/2+1);
if (votes[step][1]>votes[step][0]) {
candidatesResults[0]-=cityValues[step];
candidatesResults[1]+=cityValues[step];
}
else {
candidatesResults[1]-=cityValues[step];
candidatesResults[0]+=cityValues[step];
}
}
//the first to shark
else if (stateChoice == 2) {
//shark become the first
if (votes[step][1]>votes[step][0]) {
int move = Math.abs(votes[step][1]-votes[step][2])/2+1;
if (votes[step][2]+move > votes[step][0]) moveNum -= move;
else moveNum -= (move + votes[step][0]-(votes[step][2]+move)+1);
candidatesResults[1]+=cityValues[step];
}
else {
int move = Math.abs(votes[step][0]-votes[step][2])/2+1;
if (votes[step][2]+move > votes[step][1]) moveNum -= move;
else moveNum -= (move + votes[step][1]-(votes[step][2]+move)+1);
candidatesResults[0]+=cityValues[step];
}
candidatesResults[2]-=cityValues[step];
}
}
}
solution.cpp:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int T, N, finalVotes[10], expectResults[3][10], answer;
void dfs(int currentState, int votedA, int votedB, int votedC, int personsChanged){
if (answer <= personsChanged){
return;
}
// 可以考虑每个州都去比较一次最终结果,如果已经胜出,后续自然就不必动员了。这里偷懒不麻烦了
if (currentState == N){
if (votedC > votedA && votedC > votedB){
answer = personsChanged;
}
return;
}
// 对预期初选人数排序,根据排序结果确定该州的策略
int max, middle, min;
if (expectResults[0][currentState] >= expectResults[1][currentState]){
max = expectResults[0][currentState];
middle = expectResults[1][currentState];
}
else{
max = expectResults[1][currentState];
middle = expectResults[0][currentState];
}
min = expectResults[2][currentState];
//考虑3种情况:C反超两人;第二名超过第一名;保持原状
// C反超两人
int catch1st = (max + min) / 2 + 1;
if (catch1st > middle){
dfs(currentState + 1, votedA, votedB, votedC + finalVotes[currentState], personsChanged + ((max + min) / 2 + 1 - min));
}
else {
dfs(currentState + 1, votedA, votedB, votedC + finalVotes[currentState], personsChanged + ((max + min) / 2 + 1 - min) + (middle - catch1st + 1));
}
// 保持原状,和让第二名超过第一名,这两种情况,都分A、B谁是预期第一名两种可能处理
if (max == expectResults[0][currentState]){
dfs(currentState + 1, votedA + finalVotes[currentState], votedB, votedC, personsChanged);
dfs(currentState + 1, votedA, votedB + finalVotes[currentState], votedC, personsChanged + ((max + middle) / 2 + 1 - middle));
}
else {
dfs(currentState + 1, votedA, votedB + finalVotes[currentState], votedC, personsChanged);
dfs(currentState + 1, votedA + finalVotes[currentState], votedB, votedC, personsChanged + ((max + middle) / 2 + 1 - middle));
}
}
int main(int argc, char** argv) {
freopen("sample_input.txt", "r", stdin);
setbuf(stdout, NULL);
scanf("%d", &T);
for (int test_case = 1; test_case <= T; ++test_case){
scanf("%d", &N);
for (int i = 0; i < N; i++){
scanf("%d", &finalVotes[i]);
}
for (int person = 0; person < 3; person++){
for (int state = 0; state < N; state++){
scanf("%d", &expectResults[person][state]);
}
}
answer = 99999999;
dfs(0, 0, 0, 0, 0);
printf("#%d %d\n", test_case, answer);
}
return 0;
}
solution_min.cpp:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int T, N, votes[10], results[3][10], answer;
void dfs(int current, int votedA, int votedB, int votedC, int persons){
if (answer <= persons)
return;
if (current == N){
if (votedC > votedA && votedC > votedB)
answer = persons;
return;
}
int max = results[0][current] > results[1][current] ? results[0][current] : results[1][current];
int middle = results[0][current] < results[1][current] ? results[0][current] : results[1][current];
int personsNeeded = (max + results[2][current]) / 2 + 1;
if (personsNeeded <= middle)
personsNeeded += middle - personsNeeded + 1;
dfs(current + 1, votedA, votedB, votedC + votes[current], persons + personsNeeded - results[2][current]);
if (max == results[0][current]){
dfs(current + 1, votedA + votes[current], votedB, votedC, persons);
dfs(current + 1, votedA, votedB + votes[current], votedC, persons + ((max + middle) / 2 + 1 - middle));
}
else {
dfs(current + 1, votedA, votedB + votes[current], votedC, persons);
dfs(current + 1, votedA + votes[current], votedB, votedC, persons + ((max + middle) / 2 + 1 - middle));
}
}
int main(int argc, char** argv) {
freopen("sample_input.txt", "r", stdin);
setbuf(stdout, NULL);
scanf("%d", &T);
for (int test_case = 1; test_case <= T; ++test_case){
scanf("%d", &N);
for (int i = 0; i < N; i++)
scanf("%d", &votes[i]);
for (int person = 0; person < 3; person++)
for (int state = 0; state < N; state++)
scanf("%d", &results[person][state]);
answer = 99999999;
dfs(0, 0, 0, 0, 0);
printf("#%d %d\n", test_case, answer);
}
return 0;
}