题意:有n(1<=n<=50) 堆盘子,第i堆盘子有hi个盘子(1 <= hi <= 50),从上到下直径不减.所有盘子的直径均不超过10000。有如下两种操作.
split : 把一堆盘子从某个位置处分成上下两堆。
join:把一堆盘子a放到另一堆盘子b的顶端,要求是a底部的盘子的直径不超过b顶端盘子的直径.
你的任务是用最少的操作把所有盘子叠成一堆.
其实应该很容易想到,如果我们把不同的堆刷成不同的颜色。那么操作数就与最终状态的相邻异色对的数量ans有关 写几组数据后可以发现最终答案为2*ans-n+1。
那么 我们就可以把问题转化成为求最小异色对数。
如果定义dp[i][j] 为处理完半径小于等于i的圆盘 放在最下面的圆盘为第j种颜色。 这样定义的正确性和转移方程都很容易写。
但是因为i=10000 所以单次询问复杂度为O(10000*(n^2)) 再加上多组输入 数据变态一点(其实好像数据很弱,官方下载的数据全都是单组输入)很有可能超时。
然后因为最多只有2500个盘子 我们其实可以离散化一下。
然后就很(超)好(麻)写(烦)了。
WA了不知道多少发了 结果发现状态转移时没取最小值 ORZ。
代码写得很乱 没有可参考性
# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
#include<vector>
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
int dp[2505][50];// dp[i][j]表示前i种直径的圆盘处理完后 第i种圆盘以第j堆结尾时的最小异色对数
class node
{
public:
int r,sum,id;
bool operator < (const node