1. 程式人生 > >凸多邊形三角劃分

凸多邊形三角劃分

傳送門 (LOJ升級版)

這道題雖然是基礎的區間DP,但是還是很值得一說的。

我們用dp[i][j]表示第i個點到第j個點劃分的最大值。注意我們只枚舉了兩個端點,第三個頂點是我們列舉的那個k,之後發現k這個頂點可以把整個區間分成兩塊,我們就可以進行區間DP了。

只不過這道題要使用高精度。需要自己過載一下,對於賦INF值的話,我們直接把長度設為極大值即可。(好像還能用int128過)

看一下程式碼。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include
<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 10005; const ll INF = 1000000009; ll read() { ll ans = 0,op = 1;
char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct big { int f[105],len; big() { memset(f,
0,sizeof(f)),len = 0; } void modi(ll g) { if(g >= INF) { len = 50; return; } while(g) f[len++] = g % 10,g /= 10; while(!f[len] && len > 0) len--; } big operator * (const big &g) const { big c; c.len = len + g.len + 1; rep(i,0,len) rep(j,0,g.len) c.f[i+j] += f[i] * g.f[j]; rep(i,0,c.len-1) c.f[i+1] += c.f[i] / 10,c.f[i] %= 10; while(!c.f[c.len] && c.len > 0) c.len--; return c; } big operator + (const big & g) const { big c; c.len = max(len,g.len) + 1; rep(i,0,c.len) c.f[i] = f[i] + g.f[i]; rep(i,0,c.len-1) c.f[i+1] += c.f[i] / 10,c.f[i] %= 10; while(!c.f[c.len] && c.len > 0) c.len--; return c; } void print() { per(i,len,0) printf("%d",f[i]);enter; } }dp[105][105],a[105]; ll n,x; big bmin(const big &a,const big &b) { if(a.len != b.len) return (a.len < b.len) ? a : b; per(i,a.len,0) if(a.f[i] != b.f[i]) return (a.f[i] < b.f[i]) ? a : b; return a; } int main() { n = read(); rep(i,1,n) x = read(),a[i].modi(x); rep(L,2,n-1) { rep(i,1,n-L) { int j = i + L; dp[i][j].modi(INF); rep(k,i+1,j-1) dp[i][j] = bmin(dp[i][j],dp[i][k] + dp[k][j] + a[i] * a[j] * a[k]); } } dp[1][n].print(); return 0; }