chika和蜜柑
(1)思路:贪心
按照甜度最大的来取(从大到小排序),遇到相同甜度的去酸度最小(从小到大排序),可以用sort也可以用优先队列来写;
(2)测试数据
3 2
1 3 4
2 2 5
(3)代码(贪心思想 + sort)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n;
// 在C++的语法里面,可以直接用 结构体名字来定义变量,而无需用typedef重命名
struct migan {
ll sweet;
ll sour;
};
bool cmp(migan a, migan b) {
if (a.sweet == b.sweet) {
return a.sour < b.sour;
} else {
return a.sweet > b.sweet;
}
}
int k;
migan nums[200005];
ll sumSweet;
ll sumSour;
int main (){
cin >> n >> k;
for (int i = 0; i < n; ++i) {
cin >> nums[i].sour;
}
for (int i = 0; i < n; ++i) {
cin >> nums[i].sweet;
}
sort(nums, nums + n, cmp);
for (int i = 0; i < k; ++i) {
sumSweet += nums[i].sweet;
sumSour += nums[i].sour;
}
cout << sumSour << ' ' << sumSweet;
return 0;
}
you和帆船(枚举)
(1)测试数据
2
1 0
0 1
(2)代码(思路在注释中)
// 直接枚举
//2 ≤n ≤2000 可以枚举
#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 2005;
int a[N][2];
double minDis = 1e9; //最小路径和
int main () {
double tmp;
cin >> n;
// 输入宝藏的地点
for (int i = 0; i < n; ++i) {
cin >> a[i][0] >> a[i][1]; // 0代表x坐标,1代表y坐标
}
// 搜寻两个宝藏,三条边,(0,0)起始点-->第一个宝藏-->第二个宝藏-->回到起始点(0,0)
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
// 距离公式
minDis = min(minDis, sqrt(a[i][0] * a[i][0] + a[i][1] * a[i][1]) +sqrt (a[j][0] * a[j][0] + a[j][1] * a[j][1]) + sqrt((a[i][0] - a[j][0]) * (a[i][0] - a[j][0]) + (a[i][1] - a[j][1]) * (a[i][1] - a[j][1])));
}
}
cout << fixed << setprecision(6) << minDis;
return 0;
}
数位染色(状压枚举/dfs)
(1)思路:
x的范围不超过1e18,所以x最多只有19位数字。O(n2^n)状压枚举每位选或不选即可通过。(每个位置上两种状态0或1,多少位置,2的多少次方)还需要遍历n; 代码中有注释,可以先看一遍代码,方便理解
(2)测试数据
1234567
(3)代码(状压---状态压缩)
// 状压基本模板
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int zt[22]; //代表每一位上的数字,等下要跟状态相结合
int sum, ans;
ll num;
// ans 是原始的数,每位数字的总和
// sum 是后面染色的数字和
// 我们的判断依据就是,若sum * 2 == ans,说明染色的数字和==未染色数字和 (仔细想想,即染色数字和就是总和的一半)
int main () {
int j = 0;
cin >> num; //输入这个数字 123456
// 将每一位拆解开
while (num) {
zt[j++] = num % 10; // 从最低位开始,一个一个存进zt数组中( 倒着的) 654321
ans += num % 10; //再将每一位的数字求和
num /= 10; // 求下一位数字
}
// 最后得出的j,就知道有多少位了
// 枚举状态
// 1 << j 即二进制 左移 就是乘,右移即除,代表2^j个状态
for (int i = 0; i < 1 << j; ++i) {
int p = i; // 取出i(十进制)
sum = 0;
//转换成二进制(状态),并且与位置上的数字结合
// p % 2 就是从最低位开始,取二进制数 010101...
// k = 0,也是最低位
// 求和 1 代表染色,0代表不染色,染色就把和加上
for (int k = 0; k < j; ++k) {
sum += p % 2 * zt[k];
p /= 2; // 求下一位
}
if (sum * 2 == ans) {
cout << "Yes";
return 0;
}
}
cout << "No";
return 0;
}
- 对二进制处理的时候,&1,>> 1,位运算比 % /更快
// 状压基本模板
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int zt[22]; //代表每一位上的数字,等下要跟状态相结合
int sum, ans;
ll num;
// ans 是原始的数,每位数字的总和
// sum 是后面染色的数字和
// 我们的判断依据就是,若sum * 2 == ans,说明染色的数字和==未染色数字和 (仔细想想,即染色数字和就是总和的一半)
int main () {
int j = 0;
cin >> num; //输入这个数字 123456
// 将每一位拆解开
while (num) {
zt[j++] = num % 10; // 从最低位开始,一个一个存进zt数组中( 倒着的) 654321
ans += num % 10; //再将每一位的数字求和
num /= 10; // 求下一位数字
}
// 最后得出的j,就知道有多少位了
// 枚举状态
// 1 << j 即二进制 左移 就是乘,右移即除,代表2^j个状态
for (int i = 0; i < 1 << j; ++i) {
int p = i; // 取出i(十进制)
sum = 0;
//转换成二进制(状态),并且与位置上的数字结合
// p % 2 就是从最低位开始,取二进制数 010101...
// k = 0,也是最低位
// 求和 1 代表染色,0代表不染色,染色就把和加上
for (int k = 0; k < j; ++k) {
sum += (p & 1) * zt[k];
p = p >> 1; // 求下一位
}
if (sum * 2 == ans) {
cout << "Yes";
return 0;
}
}
cout << "No";
return 0;
}
(4)代码(DFS)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll sum;
ll x;
int getSum (ll x) {
int res = 0;
while (x) {
res += x % 10;
x /= 10;
}
return res;
}
int judge = 0; // 找到一个方案数,正好染色的数字之和等于总和的一半,就为true
//x 代表当前这个数字(后面几个已经选过了,还有哪些位置还没有选,
//tmp 代表选了后面几位,我会选到什么 (已经选到的数字的和)
void dfs(ll x, ll tmp) { //12345 取 13
if (x == 0 || tmp * 2 >= sum) {
if (tmp * 2 == sum) {
judge = 1;
}
return ;
}
// 当前x%10的数不取,直接到下一个数
dfs(x / 10, tmp);
// 当前x%10的数取
dfs(x / 10, tmp + x % 10);
}
int main () {
cin >> x; // 输入的数字
sum = getSum(x); // 求位置上的数字的和
dfs(x, 0);
if (judge) cout << "Yes";
else cout << "No";
return 0;
}