Codeforces C. Elections(贪心枚举三分)
题目描述:
C. Elections
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
As you know, majority of students and teachers of Summer Informatics School live in Berland for the most part of the year. Since corruption there is quite widespread, the following story is not uncommon.
Elections are coming. You know the number of voters and the number of parties — nn and mm respectively. For each voter you know the party he is going to vote for. However, he can easily change his vote given a certain amount of money. In particular, if you give ii-th voter cici bytecoins you can ask him to vote for any other party you choose.
The United Party of Berland has decided to perform a statistical study — you need to calculate the minimum number of bytecoins the Party needs to spend to ensure its victory. In order for a party to win the elections, it needs to receive strictly more votes than any other party.
Input
The first line of input contains two integers nn and mm (1≤n,m≤30001≤n,m≤3000) — the number of voters and the number of parties respectively.
Each of the following nn lines contains two integers pipi and cici (1≤pi≤m1≤pi≤m, 1≤ci≤1091≤ci≤109) — the index of this voter's preferred party and the number of bytecoins needed for him to reconsider his decision.
The United Party of Berland has the index 11.
Output
Print a single number — the minimum number of bytecoins needed for The United Party of Berland to win the elections.
Examples
input
Copy
1 2
1 100
output
Copy
0
input
Copy
5 5
2 100
3 200
4 300
5 400
5 900
output
Copy
500
input
Copy
5 5
2 100
3 200
4 300
5 800
5 900
output
Copy
600
Note
In the first sample, The United Party wins the elections even without buying extra votes.
In the second sample, The United Party can buy the votes of the first and the fourth voter. This way The Party gets two votes, while parties 33, 44 and 55 get one vote and party number 22 gets no votes.
In the third sample, The United Party can buy the votes of the first three voters and win, getting three votes against two votes of the fifth party.
思路:
刚开始:拿到题的时候思路非常混乱,一直想着贪心的做,想找出一种决策可以在每一步最优的情况下得到全局最优。可是试了几种决策后发现不是很恰当,还曾一度以为只要1党的票数高过总票数的一半就可以胜出。事实证明,是可以胜出,但不是最优。
看来直接贪心不太容易,怎么办呢?
首先想到我们不知道1党要得到多少票才能获胜,直接的想法是枚举这个票数k,最少1票最多n票,1党的票数要大于等于k,要使1党获胜,那其他党的票数就要小于k。算出每个k对应的最小花费的最小值,就是最终答案,时间复杂度为O(\(n^2\))。
实现方式有两种,第一种是以每个选民为着眼点,把选民按照收买价格从小到大排序(贪心的思想),用一个数组记录每个党的得票数,遍历选民只要改选民的党的票数\(\geq\)k,就收买这个选民,对应的这个党的票数就会减一,1党票数就会加一,并给选民做上标记,遍历完后如果1党票数\(\geq\)k,就算出这个k下的结果,如果还不够,就再遍历一遍,收买未收买的选民直到满足条件。
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt[max_n];
int check[max_n];
struct node
{
int f;
long long mon;
};
node a[max_n];
int cnta = 0;
int cmp(node a,node b)
{
return a.mon<b.mon;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
a[cnta].f = party;
a[cnta].mon = money;
cnta++;
cnt[party]++;
check[party] = 0;
}
}
sort(a,a+cnta,cmp);
for(int k = 1;k<=n;k++)
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
memset(cnt,0,sizeof(cnt));
for(int i = 0;i<cnta;i++)
{
cnt[a[i].f]++;
}
for(int i = 0;i<=cnta;i++)
{
if(cnt[a[i].f]>=k)
{
total += a[i].mon;
cnt[a[i].f]--;
check[i] = 1;
s++;
}
}
if(s>=k)
{
minm = min(minm,total);
}
else
{
for(int i = 0;s<k;i++)
{
if(check[i]==0)
{
total += a[i].mon;
s++;
}
}
if(minm>total)
{
minm = total;
}
}
}
cout << minm << endl;
return 0;
}
还有一种以党为着眼点,用一个结构体vector数组记录每个党的选民投票情况,当然也要排序,思路也是枚举,只不过实现稍复杂一点。
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt = 0;
struct node
{
int id;
long long m;
};
node a[max_n];
int check[max_n];
struct voter
{
int id;
int mon;
};
vector<voter> pai[max_n];
int cmp(voter a,voter b)
{
return a.mon<b.mon;
}
int cmp2(node a,node b)
{
return a.m < b.m;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
voter v;
v.id = cnt;
v.mon = money;
a[cnt].id = cnt;
a[cnt].m = money;
cnt++;
pai[party].push_back(v);
}
}
for(int i = 2;i<=m;i++)
{
sort(pai[i].begin(),pai[i].end(),cmp);
}
sort(a,a+cnt,cmp2);
for(int k = 1;k<=n;k++)
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
for(int i = 2;i<=m;i++)
{
for(int j = 0;pai[i].size()-j>=k;j++)
{
total += pai[i][j].mon;
check[pai[i][j].id] = 1;
s++;
}
}
if(s>=k)
{
minm = min(minm,total);
}
else
{
for(int i = 0;s<k;i++)
{
if(check[a[i].id]==0)
{
total += a[i].m;
s++;
}
}
if(minm>total)
{
minm = total;
}
}
}
cout << minm << endl;
return 0;
}
实际上,这个k为自变量,收买价格为因变量是一个下凸函数,在1~n里有一个最小值,可以用三分的方法求极小值点。(关于三分的讲解见参考文章)
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt[max_n];
int check[max_n];
struct node
{
int f;
long long mon;
};
node a[max_n];
int cnta = 0;
int cmp(node a,node b)
{
return a.mon<b.mon;
}
long long cal(long long k)//相当于计算函数值,将版本一中的计算每种花费的情况独立成一个函数
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
memset(cnt,0,sizeof(cnt));
for(int i = 0; i<cnta; i++)
{
cnt[a[i].f]++;
}
for(int i = 0; i<=cnta; i++)
{
if(cnt[a[i].f]>=k)
{
total += a[i].mon;
cnt[a[i].f]--;
check[i] = 1;
s++;
}
}
if(s>=k)
{
//cout << "sum>=k" << endl;
return total;
}
else
{
//cout << "sum<k" << endl;
for(int i = 0; s<k; i++)
{
if(check[i]==0)
{
total += a[i].mon;
s++;
}
}
}
return total;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
a[cnta].f = party;
a[cnta].mon = money;
cnta++;
cnt[party]++;
check[party] = 0;
}
}
sort(a,a+cnta,cmp);
int l = 1;
int r = n;
while(r-l>3)//最后选出三个可能的极小值点
{
int mid = (l+r)>>1;
int mmid = (mid+r)>>1;
long long sum1 = cal(mid);
long long sum2 = cal(mmid);
if(sum1>sum2)//mmid更接近于极小值点
{
l = mid;
}
else//mid更接近于极小值点
{
r = mmid;
}
}
minm = cal(l);
for(int i = l+1;i<=r;i++)
{
long long ans = cal(i);
minm = min(minm,ans);
}
cout << minm << endl;
return 0;
}
参考文章:
键盘里的青春,三分算法概念,https://blog.csdn.net/qq_34374664/article/details/70141246
henuzxy,codeforces 1019 A. Elections (枚举或三分),https://blog.csdn.net/zhao5502169/article/details/81625471
闻道-问道,C. Elections(枚举+贪心),https://blog.csdn.net/a1046765624/article/details/81876925
Codeforces C. Elections(贪心枚举三分)的更多相关文章
- CodeForces - 1020C C - Elections(贪心+枚举)
题目: 党派竞争投票 有n个人,m个党派,这n个人每个人有一个想要投的党派的编号Pi,如果想要这个人改变他的想法,那么就需要花费Ci元钱. 现在你是编号为1的党派,如果你想要赢(你的票数严格大于其他党 ...
- 【BZOJ3874】[AHOI&JSOI2014]宅男计划(贪心,三分)
[BZOJ3874][AHOI&JSOI2014]宅男计划(贪心,三分) 题面 BZOJ 洛谷 题解 大力猜想一最长的天数和购买外卖的总次数是单峰的.感性理解一下就是买\(0\)次是\(0\) ...
- Codeforces 458C - Elections
458C - Elections 思路: 三分凹形函数极小值域 代码: #include<bits/stdc++.h> using namespace std; #define ll lo ...
- codeforces 578c - weekness and poorness - 三分
2017-08-27 17:24:07 writer:pprp 题意简述: • Codeforces 578C Weakness and poorness• 给定一个序列A• 一个区间的poornes ...
- CodeForces - 158B.Taxi (贪心)
CodeForces - 158B.Taxi (贪心) 题意分析 首先对1234的个数分别统计,4人组的直接加上即可.然后让1和3成对处理,只有2种情况,第一种是1多,就让剩下的1和2组队处理,另外一 ...
- POJ 1018 Communication System 贪心+枚举
看题传送门:http://poj.org/problem?id=1018 题目大意: 某公司要建立一套通信系统,该通信系统需要n种设备,而每种设备分别可以有m个厂家提供生产,而每个厂家生产的同种设备都 ...
- Codeforces Round #503 (by SIS, Div. 2) C. Elections(枚举,暴力)
原文地址 C. Elections time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- codeforces 613B B. Skills(枚举+二分+贪心)
题目链接: B. Skills time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
- 【codeforces 761C】Dasha and Password(贪心+枚举做法)
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
随机推荐
- Xamarin.Android UnauthorizedAccessException: Access to the path is denied
进行文件读写,勾选了权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" / ...
- SQLServer for linux安装
linux下安装sqlserver数据库有2种办法,第一使用yum镜像安装,第二使用rpm安装包安装 rpm安装地址为:https://packages.microsoft.com/rhel/7/ms ...
- 【C/C++开发】C++11的模板类型判断——std::is_same和std::decay
C++11的模板类型判断--std::is_same和std::decay 问题提出:有一个模板函数,函数在处理int型和double型时需要进行特殊的处理,那么怎么在编译期知道传入的参数的数据类型是 ...
- 【转】Object.keys方法之详解
一.语法 Object.keys(obj) 参数:要返回其枚举自身属性的对象 返回值:一个表示给定对象的所有可枚举属性的字符串数组 二.处理对象,返回可枚举的属性数组 let person = {n ...
- 研发的困境----DEVOPS
1.研发的困境 互联网的环境 互联网这个环境比较特别,包括现在不只是互联网,就算是被互联网赋能的这些“互联网+”的企业也在改变,用户在发生变化,用户构成的群体在发生变化,群体造成场景的变化,场景营造新 ...
- jquery关于on click事件的理解
jquery关于on click事件的理解 <pre><a style="min-width:60px; margin-left:6px;" wenzhangid ...
- 【转载,备忘】SQL Server 更改跟踪(Chang Tracking)监控表数据
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...
- Matlab 线性规划问题模型代码
线性规划问题的基本内容 线性规划解决的是自变量在一定的线性约束条件下,使得线性目标函数求得最大值或者最小值的问题. \[ \min z=\sum_{j=1}^{n} f_{j} x_{j} \] \[ ...
- Python多进程方式抓取基金网站内容的方法分析
因为进程也不是越多越好,我们计划分3个进程执行.意思就是 :把总共要抓取的28页分成三部分. 怎么分呢? # 初始range r = range(1,29) # 步长 step = 10 myList ...
- 浅谈Java Object
在Java中,所有的类都继承自Object类,因此万物皆对象?也没错! 那有人会问,我的子类继承的是父类不是Object,怎么说? 如果一个类没用显示的继承某一个类,那么他就会隐式的继承 Object ...