汽车加油问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。并证明算法能产生一个最优解。
对于给定的n和k个加油站位置,计算最少加油次数。
Input
输入数据的第一行有2 个正整数n和k(n≤5000,k≤1000),表示汽车加满油后可行驶n公里,且旅途中有k个加油站。接下来的1 行中,有k+1 个整数,表示第k个加油站与第k-1 个加油站之间的距离。第0 个加油站表示出发地,汽车已加满油。第k+1 个加油站表示目的地。
Output
将计算出的最少加油次数输出。如果无法到达目的地,则输出“No Solution!”。
Sample Input
7 7
1 2 3 4 5 1 6 6
Sample Output
4
不晓得一开始为啥不理解题意·····反正就是贪心,在最大行驶千米限制下走的越远越好
#include <bits/stdc++.h>
using namespace std;
void jiayou(int n, int k, int a[])
{
for(int i = 0; i <= k; i++)
{
if(n < a[i]) // 如果两个加油站之间的距离大于最大可行驶,直接ass
{
printf("No Solution!");
return;
}
}
int km = 0, cnt = 0;
for(int i = 0; i <= k; i++)
{
km += a[i]; // 当前行驶的距离变化放在前边
if(km > n) // 当前距离大于最大可行驶时,说明已经到了新加油的时候,所以次数加一
{
km = a[i];
cnt++;
}
}
printf("%d\n", cnt);
}
int main()
{
int n, k, a[1010];
cin>>n>>k;
for(int i = 0; i <= k; i++)
{
cin>>a[i];
}
jiayou(n, k, a);
return 0;
}
最优合并问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
给定k 个排好序的序列s1 , s2,……, sk , 用2 路合并算法将这k 个序列合并成一个序列。假设所采用的2 路合并算法合并2 个长度分别为m和n的序列需要m + n -1次比较。试设计一个算法确定合并这个序列的最优合并顺序,使所需的总比较次数最少。
为了进行比较,还需要确定合并这个序列的最差合并顺序,使所需的总比较次数最多。
对于给定的k个待合并序列,计算最多比较次数和最少比较次数合并方案。
Input
输入数据的第一行有1 个正整数k(k≤1000),表示有k个待合并序列。接下来的1 行中,有k个正整数,表示k个待合并序列的长度。
Output
输出两个整数,中间用空格隔开,表示计算出的最多比较次数和最少比较次数。
Sample Input
4
5 12 11 2
Sample Output
78 52
Hint
这个题的意思是给了四个序列进行合并,下边给出的四个数分别是四个序列的长度
根据贪心算法,最优时,应该先合并序列长度最小的, 最差时,就是应该先合并序列长度最大的
#include <bits/stdc++.h>
using namespace std;
int cmp(int a, int b) // 重写sort函数,从大到小排序
{
return a > b;
}
int main()
{
int k, a[1010], b[1010];
cin>>k;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for(int i = 0; i < k; i++)
{
cin>>a[i];
b[i] = a[i];
}
int num1 = 0, num2 = 0;
sort(a, a + k); // 从小到大进行排序, 最优
sort(b, b + k, cmp); // 从大到小进行排序, 最差
for(int i = 0; i < k - 1; i++)
{
a[i+1] = a[i] + a[i+1];
num1 += a[i+1];
sort(a+i+1, a+k);
b[i+1] = b[i] + b[i+1];
num2 += b[i+1];
sort(b+i+1, b+k, cmp); // 注意排序
}
num1 -= (k - 1); // 因为最后要减去(n-1)个1
num2 -= (k - 1);
cout<<num2<<" "<<num1<<endl;
return 0;
}
装船问题
Problem Description
王小二毕业后从事船运规划工作,吉祥号货轮的最大载重量为M吨,有10种货物可以装船。第i种货物有wi吨,总价值是pi。王小二的任务是从10种货物中挑选若干吨上船,在满足货物总重量小于等于M的前提下,运走的货物的价重比最大。
Input
输入数据的第一行有一个正整数M(0 < M < 10000),表示所有货物最大载重量。在接下来的10行中,每行有若干个数(中间用空格分开),第i行表示的是第i种货物的货物的总价值pi ,总重量wi。(pi是wi的整数倍,0 < pi , wi < 1000)
Output
输出一个整数,表示可以得到的最大价值。
Sample Input
100
10 10
20 10
30 10
40 10
50 10
60 10
70 10
80 10
90 10
100 10
Sample Output
550
#include <bits/stdc++.h>
using namespace std;
// 不能拆分是动态规划 可拆分的是贪心
int main()
{
int M, pi[1050], wi[1050], t;
double val[1050];
cin>>M;
for(int i = 0; i < 10; i++)
{
cin>>pi[i]>>wi[i];
val[i] = (pi[i] * 1.0) / wi[i];
}
for(int i = 0; i < 10; i++) // 选择排序
{
for(int j = i + 1; j <= 9; j++)
{
if(val[i] < val[j])
{
t = val[i], val[i] = val[j], val[j] = t;
t = pi[i], pi[i] = pi[j], pi[j] = t;
t = wi[i], wi[i] = wi[j], wi[j] = t;
}
}
}
int maxVal = 0, h = 0;
while(M >= 0 && h < 10)
{
if(wi[h] > M) // 当最价值比的货物比最大载重还要大时,只能装最大价值比的货物,注意与最少硬币数(动态规划)的区别
{
maxVal += M / val[h];
M = -1;
}
else
{
M -= wi[h];
maxVal += pi[h];
}
h++;
}
printf("%d\n", maxVal);
return 0;
}
区间覆盖问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
设x1 , x2 ,…… , xn 是实直线上的n 个点。用固定长度的闭区间覆盖这n 个点,至少需要多少个这样的固定长度闭区间?
对于给定的实直线上的n个点和闭区间的长度k,设计解此问题的有效算法,计算覆盖点集的最少区间数,并证明算法的正确性。
Input
输入数据的第一行有2 个正整数n和k(n≤10000,k≤100),表示有n个点,且固定长度闭区间的长度为k。接下来的1 行中,有n个整数,表示n个点在实直线上的坐标(可能相同)。
Output
输出一个整数,表示计算出的最少区间数输出。
Sample Input
7 3
1 2 3 4 5 -2 6
Sample Output
3
Hint
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, k, a[10010];
cin>>n>>k;
for(int i = 0; i < n; i++)
{
cin>>a[i];
}
sort(a, a + n);
int temp = a[0], cnt = 1; // 初始cnt为1
for(int i = 0; i < n; i++)
{
if(a[i] - temp > k)
{
cnt++;
temp = a[i]; // 更新左端点
}
}
cout<<cnt<<endl;
return 0;
}
活动选择
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
学校的大学生艺术中心周日将面向全校各个学院的学生社团开放,但活动中心同时只能供一个社团活动使用,并且每一个社团活动开始后都不能中断。现在各个社团都提交了他们使用该中心的活动计划(即活动的开始时刻和截止时刻)。请设计一个算法来找到一个最佳的分配序列,以能够在大学生艺术中心安排不冲突的尽可能多的社团活动。
比如有5个活动,开始与截止时刻分别为:
最佳安排序列为:1,4,5。
Input
第一行输入活动数目n(0<n<100);
以后输入n行,分别输入序号为1到n的活动使用中心的开始时刻a与截止时刻b(a,b为整数且0<=a,b<24,a,b输入以空格分隔)。
Output
输出最佳安排序列所包含的各个活动(按照活动被安排的次序,两个活动之间用逗号分隔)。
Sample Input
6
8 10
9 16
11 16
14 15
10 14
7 11
Sample Output
1,5,4
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, t;
cin>>n;
int s[105], e[105], num[105];
for(int i = 0; i < n; i++)
{
cin>>s[i]>>e[i];
num[i] = i + 1; // 开启一个数组记录活动的初始编号
}
for(int i = 0; i < n; i++)
{
for(int j = i + 1; j <= n - 1; j++)
{
if(e[i] > e[j])
{
t = e[i], e[i] = e[j], e[j] = t;
t = s[i], s[i] = s[j], s[j] = t;
t = num[i], num[i] = num[j], num[j] = t;
}
}
}
printf("%d", num[0]); // 该算法是只考虑最早结束的时间, 那么第一个活动在排序后一定是最早结束的
int temp = e[0];
for(int j = 1; j < n; j++)
{
if(temp <= s[j])
{
printf(",%d", num[j]);
temp = e[j];
}
}
cout<<endl;
return 0;
}