外卖员送货
题目描述
某地共有 n 个小区,各个小区编号即0, 1, 2, …, n-1,n-1个外卖员从0号小区出发分别给其它各小区送外卖,每个外卖员负责一个小区的外卖,每个外卖员都会选择到自己所负责的小区最短距离的路径去送外卖。请使用贪心算法计算出所有外卖员到各自所负责的小区的最短距离之和。
输入的第一行是整数 n,表示一共 n 个小区。
输入的第二行是整数 m,表示一共有 m 条路。
接下来输入的 m 行,每行3个整数,分别表示小区 x,小区 y,以及 x 到 y的距离。
样例输入输出
样例1
输入:
6
10
0 1 10
0 5 3
1 2 7
1 3 5
3 2 4
3 4 7
3 0 3
5 1 2
5 3 6
5 4 1
输出:
33
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n= sc.nextInt();
int m= sc.nextInt();
int [][]e=new int [n][n];
for (int i = 0; i <n; i++)
{
for(int j=0;j<n;j++)
{
if(i==j)e[i][j]=0;
else e[i][j]=Integer.MAX_VALUE;
}
}
int u,v,w;
for(int i=0;i<m;i++)
{
u=sc.nextInt();
v= sc.nextInt();
e[u][v]=sc.nextInt();
}
//Dijkstra
int k;
k=0;//邮递员从0号村庄出发
int dis[]=new int[n];
for(int i=0;i<n;i++)dis[i]=e[k][i];
int flag[]=new int[n];
flag[k]=1;//归入数组s
for (int x = 0; x < n; x++)
{
int min=Integer.MAX_VALUE;
int min_num=0;
for (int i = 0; i <n; i++)
{
if (flag[i]==0&&dis[i]<min)//没访问过且可达
{
min=dis[i];min_num=i;
}
}
flag[min_num]=1;//被确定是最短路径的点被标记
for (int i = 0; i < n; i++)
{
if (e[min_num][i]<Integer.MAX_VALUE&&dis[i]>dis[min_num]+e[min_num][i])
{
dis[i]=dis[min_num]+e[min_num][i];
}
}
}
int sum=0;
for (int i = 0; i < n; i++) {
sum+=dis[i];
}
System.out.println(sum);
}
}
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> e(n, vector<int>(n, INT_MAX));
for (int i = 0; i < n; ++i) {
e[i][i] = 0;
}
int u, v, w;
for (int i = 0; i < m; ++i) {
cin >> u >> v >> w;
e[u][v] = w;
}
vector<int> dis(n, INT_MAX);
dis[0] = 0;
vector<int> flag(n, 0);
flag[0] = 1;
for (int x = 0; x < n; ++x) {
int min_dist = INT_MAX;
int min_num = 0;
for (int i = 0; i < n; ++i) {
if (flag[i] == 0 && dis[i] < min_dist) {
min_dist = dis[i];
min_num = i;
}
}
flag[min_num] = 1;
for (int i = 0; i < n; ++i) {
if (e[min_num][i] < INT_MAX && dis[i] > dis[min_num] + e[min_num][i]) {
dis[i] = dis[min_num] + e[min_num][i];
}
}
}
int sum = 0;
for (int i = 0; i < n; ++i) {
sum += dis[i];
}
cout << sum << endl;
return 0;
}
安全培训
题目描述
大学有很多学院,现在学校为了科普普及安全知识,需要对每个学院的一位安全委员进行培训,但每个安全委员的空闲时间不同,学校想根据各个学院安全委员的空闲时间安排培训会,请使用贪心算法计算出学校需要安排最少几次培训会。
注意:不需要考虑培训会持续时间。即假设如果 X 同学空闲时间段为1 2,Y 同学空闲时间段为2 3,培训会安排在2这个时刻时X 、Y 同学均可参加。
输入的第一行是整数 n,表示该学校共有 n 个学院。
接下来输入的 n 行,每行2个整数,分别表示该安全委员空闲时间段的开始时刻和结束时刻。
样例输入输出
样例1
输入:
4
1 2
2 3
3 4
4 5
输出:
2
要解决这个问题,我们需要找到最少的培训会次数,使得每个安全委员至少能参加一次培训会。这个问题类似于经典的区间调度问题,可以使用贪心算法来解决。具体思路是:按照结束时间对区间进行排序,然后尽可能选择最早的结束时间点来安排培训会,这样可以覆盖最多的后续区间。
方法思路
- 排序区间:首先将所有安全委员的空闲时间段按照结束时间进行升序排序。这样我们可以优先处理结束时间早的区间。
- 贪心选择:初始化一个变量来记录当前安排的最后一个培训会的时间点。遍历排序后的区间,如果当前区间的开始时间大于最后一个培训会的时间点,说明需要安排一个新的培训会,并更新最后一个培训会的时间点为当前区间的结束时间。
解决代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Interval {
int start;
int end;
};
bool compareIntervals(const Interval &a, const Interval &b) {
return a.end < b.end;
}
int main() {
int n;
cin >> n;
vector<Interval> intervals(n);
for (int i = 0; i < n; ++i) {
cin >> intervals[i].start >> intervals[i].end;
}
sort(intervals.begin(), intervals.end(), compareIntervals);
int count = 0;
int last_end = -1;
for (const auto &interval : intervals) {
if (interval.start > last_end) {
++count;
last_end = interval.end;
}
}
cout << count << endl;
return 0;
}
代码解释
- 结构体定义:定义了一个
Interval
结构体,用于存储每个安全委员的空闲时间段的开始和结束时间。 - 比较函数:
compareIntervals
函数用于比较两个区间的结束时间,以便进行排序。 - 输入处理:读取输入的学院数量
n
,然后读取每个安全委员的空闲时间段,并存储在intervals
向量中。 - 排序:使用
sort
函数对intervals
向量按照结束时间进行升序排序。 - 贪心算法:初始化
count
为0,last_end
为-1。遍历排序后的区间,如果当前区间的开始时间大于last_end
,说明需要安排一个新的培训会,增加count
并更新last_end
为当前区间的结束时间。 - 输出结果:打印需要的最少培训会次数
count
。
这种方法确保了在最少次数的培训会中覆盖所有安全委员的空闲时间段,时间复杂度主要由排序决定,为O(n log n)。