Uva-1289 Stacking Plates

本文介绍了一种使用动态规划解决特定盘子堆叠问题的方法。通过统计不同大小盘子的数量及其分布,利用动态规划算法求解最优方案,减少盘子间的移动次数。

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

动态规划的一道题目,看了别人的代码之和自己实现的。首先是读入数据,统计每一堆中不同大小盘子的个数以及所有的盘子中大小不同的个数。然后统计对于每一类的盘子存在于哪些堆中以及每一堆中存在着哪些种类的盘子。紧接着,开始动态规划的过程,利用dp[i][j]表示将第1~i类的盘子全部堆好,并且最终这些盘子是放置于第j堆中,那么在堆积第i类的盘子之前肯定需要把第i-1类的盘子堆积好,所以当我们选取的第i类盘子最终的落脚点和第i-1类的盘子的最终的落脚点不同的时候,那么肯定是选取dp[i-1][k]+int(G[i].size())-exist[k][i]?1:0的最小值,当选取的第i类盘子和第i-1类盘子最终的落脚点相同的时候就选取     dp[i-1][k],并且比较得出最小值。注意上面的这种情况是当G[i]的大小为1的时候。当G[i]大小不为1的时候,出于避免重复的考虑(个人理解,如果有其他的理解欢迎在评论区交流),就直接舍弃这种情况,具体实现见如下代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
using namespace std;

set<int> G[2510];//第i类盘子所存在的堆的编号
int exist[55][2510];//第i堆中是否存在第j类的盘子
int dp[2510][55];

class Solve{

public:
	int n;
	int plate[55][55];
	int total[2510];
	int ind,amount;
	int Inf = 1047483647;
	

	void Init(){
		ind = 0;
		memset(exist,0,sizeof(exist));
		for (int i = 0; i < 2510; i++) G[i].clear();
		for (int i = 1; i <= n; i++){
			cin >> plate[i][0];
			for (int j = 1; j <= plate[i][0]; j++){
				cin >> plate[i][j];
				total[++ind] = plate[i][j];
			}
			plate[i][0] = unique(plate[i] + 1, plate[i] + 1 + plate[i][0]) - (plate[i]+1);
		}
		sort(total+1,total+ind+1);
		amount = unique(total+1, total + ind+1) - (total+1);
		for (int i = 1; i <= n; i++){
			for (int j = 1; j <= plate[i][0]; j++){
				plate[i][j] = lower_bound(total+1, total +1 + amount, plate[i][j]) - total;
				G[plate[i][j]].insert(i);
				exist[i][plate[i][j]] = 1;
			}
		}
	}

	void Deal(){
		Init();
		memset(dp,0x3f,sizeof(dp));
		for (int i : G[1]) dp[1][i] = G[1].size() - 1;
		for (int i = 2; i <= amount; i++){
			for (int j : G[i]){
				for (int k : G[i - 1]){
					if (j != k){
						dp[i][j] = min(dp[i][j], dp[i - 1][k] + int(G[i].size()) - (exist[k][i] ? 1 : 0));
					}
					else{//j==k
						dp[i][j] = min(dp[i][j], (G[i].size() == 1 )? dp[i - 1][j] : Inf);
					}
				}
			}
		}
		int ans = Inf;
		for (int j = 1; j <= n; j++) ans = min(ans, dp[amount][j]);
		cout << ans*2-(n-1) << endl;
	}
};

int main(){
	Solve a;
	int Case = 1;
	while (cin >> a.n){
		cout << "Case " << Case++ << ": ";
		a.Deal();
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值