实验8 求解最小机器重量设计问题I(动态规划)、实验11 并查集算法 求解奶酪问题(并查集)、实验12 最小生成树算法 求解全省畅通工程的最低成本问题(prim)

目录

实验8 求解最小机器重量设计问题I

问题描述:​

​实现代码:

运行结果:

原理思路:

实验11 并查集算法 求解奶酪问题

问题描述:​

 输入输出格式:​

样例:

实现代码:

原理思路:

实验12 最小生成树算法 求解全省畅通工程的最低成本问题

问题描述:

 输入输出:

原理思路:


实验8 求解最小机器重量设计问题I

问题描述:

实现代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<utility>
using namespace std;

//很像分组背包问题,但其实并不是,需要自己分析一波

const int N = 110;
int n, m, cost;//种类,供应商,最大值。

int f[N][N];//选前 i 个种类 且 总价值不超过j 的最小重量
int v[N][N];// v[种类][编号] = 重量
int w[N][N];// w[种类][编号] = 价值
vector<vector<pair<int ,int>>> path(N, vector<pair<int ,int>>(N));

int traversal(int a, int b)
{
	if (!a && !b)
	{
		return 0;
	}
	int num = f[a][b];

	//求出与上一个的差值,方便寻找
	int diff = num - traversal(path[a][b].first, path[a][b].second);

	for (int i = 1; i <= m; i++)
	{
		if (diff == v[a][i])
		{
			cout << i << " ";
			break;
		}
	}

	return f[a][b];
}


int main()
{

	cin >> n >> m >> cost;

	//读入数据
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> v[i][j];

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> w[i][j];

	//初始化,很重要,一定要想清楚
	//for (int i = 1; i <= n; i++)
	//{
	//	f[i][0] = 1e9;
	//}

	f[0][0] = 0; //可以不写

	//这里的背包是价格,重量是一般背包问题中的价值,不要理解错
	//遍历顺序,种类,背包,一种种类中的物品, 应该可以一维优化(滚动数组),但是这里为了方便理解,就用二维了	
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= cost; j++)
		{
			f[i][j] = 1e9;
			int t = f[i][j]; //记录路径判断用的t
			for (int k = 1; k <= m; k++)
			{
				// 根据差值,找出所选物品编号
				if (j >= w[i][k])
				{
					f[i][j] = min(f[i - 1][j - w[i][k]] + v[i][k], f[i][j]);
					if (t != f[i][j]) path[i][j] = { i - 1, j - w[i][k] };
				}
			}

				
		}
	puts("调试-----------------------------");

	//打印dp数组调试代码
	cout << "dp[i][j]数组:" << endl;
	for (int i = 1; i <= 3; i++)
	{
		for (int j = 1; j <= cost; j++)
			cout << f[i][j] << " ";
		cout << endl;
	}
		
	
	//打印路径,path[i][j]表示f[i][j]是由哪个状态转移而来
	cout << "路径:path[i][j]表示f[i][j]是由哪个状态转移而来" << endl;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= cost; j++)
		{
			cout << path[i][j].first << "-" << path[i][j].second << "  ";
		}
		cout << endl;
	}
	puts("------------------------------");
	puts("最终路径:");
	int t = traversal(3, cost);//打印最终路径

	cout << endl;

	cout << "最小重量为:" << f[3][cost] << endl;
}

运行结果:

原理思路:

        注释写的很详细了,就不解释了,如果不打印路径其实很简单就能写出来,用dp的话很难打印路径,其实最好还是用其他方法写比较好,这里只是提供一种思路。

实验11 并查集算法 求解奶酪问题

问题描述:

 输入输出格式:

样例:

实现代码:

#include<iostream>

using namespace std;

const int N = 1010;

typedef long long LL;

LL p[N];
LL x[N], y[N], z[N]; // 坐标

// 并查集
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

// 检查是否连通
bool check(LL a, LL b, LL r)
{
    LL dist = (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])+(z[a]-z[b])*(z[a]-z[b]);
    if (dist > 4 * r * r) return false;
    return true;
}


int main()
{
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(0);
    int t;
    cin >> t;
    int c = t;
    while (t--)
    {
        LL n, h, r;
        cin >> n >> h >> r;
        for (int i = 1; i <= n; i++) cin >> x[i] >> y[i] >> z[i];
        
        for (int i = 0; i <= n + 1; i++) p[i] = i; // 初始化
        
        for (int i = 1; i <= n; i++)
            for (int j = i + 1; j <= n; j++)
            {
                if (check(i, j, r)) p[find(i)] = find(j);
            }
        
        // 把上下表面外的空间也看作是两个空洞, 0位置为下,n + 1 的位置为上
        for (int i = 1; i <= n; i++) if (z[i] <= r) p[find(i)] = find(0);
        for (int i = 1; i <= n; i++) if (z[i] >= h - r) p[find(i)] = find(n + 1);


        // 查看上下表面当作的两个空洞是否连通
        if (find(0) == find(n + 1)) puts("Yes");
        else puts("No");
        
    }
    
    return 0;
}

原理思路:

        并查集写法,把上下表面外的空间也看作为一个空洞,判断两个空洞是否相连,若相连则合并到一起,记得把和上下底面相连的也合并到一起,最好判断上下面是否相通即可,我这里用索引0位置表示下底面外的空间,1位置表示上面外的空间。(记得开long long)

实验12 最小生成树算法 求解全省畅通工程的最低成本问题

问题描述:

 输入输出:

 实现代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 110, INF = 0x3f3f3f3f;

int g[N][N];
int dist[N];
int n;

int prim()

{
    memset(dist, 0x3f, sizeof dist);
    bool st[N] = {false};

    int res = 0;
    dist[1] = 0;
    for (int i = 0; i < n; i++)
    {
        int t = -1;

        for (int j = 1; j <= n; j++)
        {
            if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
        }      

        if (i && dist[t] == INF) return INF;        

        if (i) res += dist[t];

        st[t] = true;
     
        for (int j = 1; j <= n; j++)
        {
            dist[j] = min(dist[j], g[t][j]);
        }
    }    
    return res;
}

int main()
{
    while (cin >> n)
    {
        memset(g, 0x3f, sizeof g);

        if (n == 0) break;
       
        for (int i = 1; i <= n; i++)
        {
            int a, b, w, c;
            cin >> a >> b >> w >> c;
            if (c == 1) w = 0;
            g[a][b] = g[b][a] = w;
        }
    
        int t = prim();
        if (t == INF) puts("没有");
        else cout << t << endl;
    }
}

原理思路:

        prim算法而已,已经修好路的,就把边的权重赋值为0即可,还有注意这里st数组放进prim函数里,平时prim就用一次初始化一次就行,习惯了写在外面,现在有多个样例,会用到多次prim算法,所以每次都要初始化一下,这个错误找了半天,我就说为什么第一个样例结果就是对的,我还以为是代码某个地方写错了,调试了半天才发现这个问题,也算是长了个记性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cosmoshhhyyy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值