算法设计与分析课程实验——贪心法实验报告

这篇实验报告探讨了贪心算法在解决单源最短路径问题和多机调度问题中的应用。通过迪杰斯特拉算法实现了单源最短路径的计算,并对算法的时间复杂性进行了分析,指出在可能存在多条边的情况下,存储最短边的重要性。同时,报告还介绍了多机调度问题的贪心解决方案,详细展示了任务分配过程,并分析了算法的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

贪心法实验报告

实验内容

  1. 单源最短路径问题,并对算法进行时间复杂性分析。

  2. 实现多机调度问题,并对算法进行时间复杂性分析。

【注】均以表格形式显示结果,再用文字说明问题的解并给出解的标准形式

实验目的

  1. 掌握贪心算法求解问题的一般特征和步骤;

  2. 使用贪心算法编程,求解单源最短路径问题和多机调度问题。

程序清单

/*
 * @Description: 单源最短路问题的贪心算法
 * @version: 
 * @Author: 
 * @Date: 2021-05-20 20:00:53
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-05-20 20:30:35
 */
// 迪杰斯特拉算法
// ! 可能有重复边,需要存两个结点间最短的的那个。
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
#include <cstring>
#define MAX 1 << 30
int map[2001][2001];
using namespace std;
int main()
{
    int num_node, num_edge;
    cout << "Please input the number of node and edge:\n"
         << endl;
    cin >> num_edge >> num_node;
    // 初始化矩阵
    for (int i = 0; i <= num_node; i++)
    {
        for (int j = 0; j <= num_node; j++)
            map[i][j] = MAX;
    }
    // 输入边和权值
    for (int i = 0; i < num_edge; i++)
    {
        int start, end, length;
        cin >> start >> end >> length;
        if (map[start][end] > length)
            map[start][end] = length;
    }
    // visit数组标记该结点是否已经进地杰斯特拉算法的已判断的集合,初始化为false
    vector<bool> visit(num_node + 1, false);
    // distance数组记录起点到该结点的最短距离为多少,初始化为起点到各点的距离
    vector<int> distance(num_node + 1, MAX);
    for (int i = 0; i <= num_node; i++)
        distance[i] = map[1][i];
    // 将起点标记为true, 起点到起点的距离为0
    visit[1] = true;
    distance[1] = 0;
    cout << "\n-------------------------" << endl;
    cout << "1th" << endl;
    for (int i = 1; i <= num_node; i++)
    {
        if (!visit[i] && distance[i] == MAX)
            cout << i << "\tMAX" << endl;
        else if (!visit[i] && distance[i] != MAX)
            cout << i << "\t" << distance[i] << endl;
    }
    int count = 2;
    for (int i = 1; i <= num_node; i++)
    {
        // 记录当前距离最小的结点是哪个,最短距离为多少
        int min_node = 0, mindis = MAX;
        // 找到当前未标记的距离最小结点
        for (int j = 1; j <= num_node; j++)
            if (!visit[j] && distance[j] < mindis)
            {
                mindis = distance[j];
                min_node = j;
            }
        if (min_node == 0)
            continue;
        // 把该结点标记为已进入集合
        visit[min_node] = true;
        // 更新未进入集合的结点的距离数组,为下一轮的选择最小点做准备
        for (int j = 1; j <= num_node; j++)
        {
            if (!visit[j] && distance[j] > distance[min_node] + map[min_node][j])
                distance[j] = distance[min_node] + map[min_node][j];
        }
        cout << "\n-------------------------" << endl;
        cout << count << "th" << endl;
        count++;
        for (int i = 1; i <= num_node; i++)
        {
            if (!visit[i] && distance[i] == MAX)
                cout << i << "\tMAX" << endl;
            else if (!visit[i] && distance[i] != MAX)
                cout << i << "\t" << distance[i] << endl;
        }
    }
    cout << "So far, all the nodes are selected into the set\n"
            "The distance from the source point to the end point is:"
         << endl;
    cout << distance[num_node] << endl;
    system("pause");
    return 0;
}
/* 
9 6
1 2 1
1 3 12
2 3 9
2 4 3
4 3 4
3 5 5
4 5 13
4 6 15
5 6 4
 */
// 时间复杂度为O(n^2)
/*
 * @Description: 多机调度问题
 * @version:
 * @Author:
 * @Date: 2021-05-20 18:22:21
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-05-20 19:09:07
 */
 // 即多个需要执行时间不同的作业,在若干机器上运行,求所需的最小时间
 // t[]存储处理时间,且从大到小排序
 // d[]存储m台机器的空闲时间
 // S[i]以队列的形式存储机器i的处理作业
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
bool cmp(const pair<int, int> &a, const pair<int, int> &b)
{
	return a.second > b.second;
}
void MultiMachine(vector<pair<int, int>> &t, int m)
{
	sort(t.begin(), t.end(), cmp);
	// 存储各个机器处理的作业序号
	vector<vector<int>> S(m);
	// 存储各机器的空闲时间
	vector<int> d(m, 0);
	// 记录作业数
	int n = t.size();
	int i, j, k;
	// 安排前m个作业
	for (i = 0; i < m && i < n; ++i)
	{
		S[i].push_back(t[i].first);
		d[i] = t[i].second;
	}
	// 依次安排后续作业
	for (i = m; i < n; ++i)
	{
		// 找出最先空闲的机器,k用来遍历,j保存当前最早
		for (j = 0, k = 1; k < m; ++k)
			if (d[k] < d[j])
				j = k;
		// 将当前作业插入到找出的最先空闲的机器队列中
		S[j].push_back(t[i].first);
		// 空闲时间更新为+=当前作业的处理时间
		d[j] += t[i].second;
	}
	for (int i = 0; i < m; ++i)
	{
		cout << i + 1 << "th machine's task(s):" << ends;
		for (auto it = S[i].cbegin(); it != S[i].cend(); ++it)
			cout << "task" << *it << "\t";
		cout << endl;
	}
	cout << "\nThe time required is " << ends;
	int max = d[0];
	for (int i = 1; i < m; ++i)
		if (d[i] > max)
			max = d[i];
	cout << max << endl;
}
int main(void)
{
	int num_task, num_machine;
	cout << "Please input the number of task and machine:\n"
		<< endl;
	cin >> num_task >> num_machine;
	vector<pair<int, int>> t;
	for (int i = 0; i < num_task; ++i)
	{
		int time;
		cin >> time;
		t.push_back(make_pair(i + 1, time));
	}
	cout << endl;
	MultiMachine(t, num_machine);
	system("pause");
	return 0;
}
/*
7 3
2 14 4 16 6 5 3
 */
// 该算法
// 排序的时间复杂度为O(nlogn)
// 完成前m个任务分配是O(m)
// 完成剩余任务的分配时间复杂度是O(n*m)

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rPO0nrff-1621514332079)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20210520202832846.png)]

在这里插入图片描述

分析与思考

  1. 第一个问题调试过程中出现的问题是,考虑到可能在抽象的图中不存在一对结点中存在多条边的情况,但是在实际问题中可能大量存在,所以采取了一种策略,即两点之间只存取最短的那条边的权值
  2. 第二个问题开始没有保存任务的最初编号,随后便使用pair组成键值对,保存原编号
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jian圣楠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值