题目链接:https://zoj.pintia.cn/problemsets/91827364500/problems/91827368971
题意:将一个多边形分成多个三角形,求最小代价
解题思路:
参考
首先是凸包的判断
Andrew算法:
struct Point{
int x,y;
Point(){}
Point(int xx,int yy):x(xx),y(yy){}
void read(){
scanf("%d%d",&x,&y);
}
bool operator < (const Point &other)const{
if(x == other.x)
return y < other.y;
return x < other.x;
}
Point operator - (const Point &other)const{
return Point(x - other.x,y - other.y);
}
};
Point p[400],ch[400];
int n;
double Cross(Point A,Point B){
return A.x * B.y - A.y * B.x;
}
//当返回的值小于n时,说明该多边形非凸包
int ConvexHull(){
sort(p,p+n);
int cnt = 0;
for(int i = 0; i < n; i++){
while(cnt > 1 && Cross(ch[cnt-1] - ch[cnt-2],p[i] - ch[cnt-2]) <= 0) cnt--;
ch[cnt++] = p[i];
}
int k = cnt;
for(int i = n-2; i >= 0; i--){
while(cnt > k && Cross(ch[cnt-1] - ch[cnt-2],p[i] - ch[cnt-2]) <= 0) cnt--;
ch[cnt++] = p[i];
}
if(n > 1) cnt--;
return cnt;
}
DP部分:
使用区间DP,dp[i][j]表示从顶点i到顶点j围成的多边形切割成三角形所需要的最小代价。
那么转移方程就是
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost(i,k)+cost(k,j));
其中k为i到j之间的顶点
同时要注意初始化时候的细节问题
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<algorithm>
#include<math.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int n, mod;
struct Point {
int x, y;
Point() {}
Point(int xx, int yy) :x(xx), y(yy) {}
void read() {
scanf("%d%d", &x, &y);
}
bool operator < (const Point& other)const {
if (x == other.x)
return y < other.y;
return x < other.x;
}
Point operator - (const Point& other)const {
return Point(x - other.x, y - other.y);
}
};
Point p[400], ch[400];
int f[400][400];
int dp[400][400];
int calc(Point a, Point b) {
return (abs(a.x + b.x) * abs(a.y + b.y)) % mod;
}
double Cross(Point A, Point B) {
return A.x * B.y - A.y * B.x;
}
int ConvexHull() {
sort(p, p + n);
int cnt = 0;
for (int i = 0; i < n; i++) {
while (cnt > 1 && Cross(ch[cnt - 1] - ch[cnt - 2], p[i] - ch[cnt - 2]) <= 0) cnt--;
ch[cnt++] = p[i];
}
int k = cnt;
for (int i = n - 2; i >= 0; i--) {
while (cnt > k && Cross(ch[cnt - 1] - ch[cnt - 2], p[i] - ch[cnt - 2]) <= 0) cnt--;
ch[cnt++] = p[i];
}
if (n > 1) cnt--;
return cnt;
}
int main() {
while (scanf("%d%d", &n, &mod) != EOF) {
memset(f, 0, sizeof(f));
memset(p, 0, sizeof(p));
memset(ch, 0, sizeof(ch));
for (int i = 0; i < n; i++) {
p[i].read();
}
if (n == 3) {
cout << 0 << endl;
continue;
}
if (ConvexHull() < n) {
cout << "I can't cut." << endl;
continue;
}
//计算两点间代价
for (int i = 0; i < n; i++) {
for (int j = i + 2; j < n; j++) {
f[i][j] = f[j][i] = calc(ch[i], ch[j]);
}
}
//初始化dp 相邻置为0 其他置为INF
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = INF;
}
dp[i][(i + 1) % n] = 0;
}
//处理顶点i到j围成的多边形分割成三角形的最小代价
for (int i = n - 3; i >= 0; i--) {
for (int j = i + 2; j < n; j++) {
for (int k = i + 1; k < j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + f[i][k] + f[k][j]);
}
}
}
cout << dp[0][n - 1] << endl;
}
return 0;
}