LOJ 10149 凸多边形的划分

题目大意

给定一个具有 (n) 个顶点的凸多边形,将顶点从 (1)(n) 标号,顶点 (i) 的权值为一个正整数 (a_i) 。将这个凸多边形划分成 (n-2) 个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。
其中, (3 leq n leq 50)(1 leq a_i < 10^9)

题解

(f(i,j)) 表示点 (i,i+1,i+2,...j) 组成的凸多边形内进行划分的最小权值乘积和。
(f(i,j) = minlimits_{i < k < j} left{f(i,k) + f(k,j) + a_i a_k a_j ight})
如下图:

也就是划分出粉色三角形,并合并蓝色多边形的贡献 。
但如果连接 (ik) 不是最优的呢?其实不连接的情况也可以转移出来,画个图就知道了。(然而自己当时想了30min,一直怀疑这样做的可行性)
所以我们设计状态的时候,当我们觉得某种情况无法转移出来时,要仔细想想是否能从别的情况得到,而不是轻易否定这种状态设计。

#include <cstdio>
#include <cstring>
#include <algorithm>

using std::memset;
using std::min;
using std::max;

#define MAX_N (50 + 5)

struct Big_Number
{
	int bit[35];
	int len;
	
	Big_Number()
	{
		memset(bit, 0, sizeof bit);
		len = 1;
	}
	
	Big_Number operator = (int num)
	{
		memset(bit, 0, sizeof bit);
		len = 0;
		do
		{
			bit[++len] = num % 10;
			num /= 10;
		}
		while (num);
		return *this;
	}
	
	bool operator < (const Big_Number & x) const
	{
		if (len != x.len) return len < x.len;
		for (int i = len; i; --i)
		{
			if (bit[i] != x.bit[i]) return bit[i] < x.bit[i];
		}
		return false;
	}
	
	Big_Number operator + (const Big_Number & x) const
	{
		Big_Number res;
		res.len = max(len, x.len);
		for (int i = 1; i <= res.len; ++i)
		{
			res.bit[i] += bit[i] + x.bit[i];
			if (res.bit[i] >= 10)
			{
				++res.bit[i + 1];
				res.bit[i] -= 10;
			}
		}
		while (res.bit[res.len + 1])
		{
			++res.len;
			if (res.bit[res.len] >= 10)
			{
				++res.bit[res.len + 1];
				res.bit[res.len] -= 10;
			}
		}
		return res;
	}
	
	Big_Number operator * (const Big_Number & x) const
	{
		Big_Number res;
		res.len = len + x.len - 1;
		for (int i = 1; i <= res.len; ++i)
		{
			for (int j = min(i, len); j; --j)
			{
				res.bit[i] += bit[j] * x.bit[i - j + 1];
			}
			if (res.bit[i] >= 10)
			{
				res.bit[i + 1] += res.bit[i] / 10;
				res.bit[i] %= 10;
			}
		}
		while (res.bit[res.len + 1])
		{
			++res.len;
			if (res.bit[res.len] >= 10)
			{
				res.bit[res.len + 1] += res.bit[res.len] / 10;
				res.bit[res.len] %= 10;
			}
		}
		return res;
	}
};

int n;
Big_Number a[MAX_N];
Big_Number f[MAX_N][MAX_N];

Big_Number Min(Big_Number x, Big_Number y)
{
	if (x < y) return x;
	return y;
}

int main()
{
	scanf("%d", &n);
	int tmp;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &tmp);
		a[i] = tmp;
	}
	for (int i = n - 2; i; --i)
	{
		for (int j = i + 2; j <= n; ++j)
		{
			f[i][j].len = 30;
			memset(f[i][j].bit, 0x7f, sizeof f[i][j].bit);
			for (int k = i + 1; k < j; ++k)
			{
				f[i][j] = Min(f[i][j], f[i][k] + f[k][j] + a[i] * a[k] * a[j]);
			}
		}
	}
	for (int i = f[1][n].len; i; --i)
	{
		printf("%d", f[1][n].bit[i]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/kcn999/p/13504249.html