ZOJ-3537

题目大意:给你一个n (n<=300) 边形,给出它所有的顶点坐标,让你把它划分成n-2个三角形的花费最小值,顶点 a 和 b 相连的花费为

abs(a.x+b.x)*abs(a.y+b.y)。 如果是凹多边形输出无解。

 

思路:先跑个凸包判断是不是凸多边形,跑完之后点的顺序是逆时针的,我们考虑区间dp,dp[ i ][ j ]表示,从顶点 i 沿多边形的边逆时针跑到

顶点 j 所形成的折线和 直线i->j,所围成的多边形分割成小三角形所需要的花费。

状态转移方程: dp[ i ][ j ]=min(dp[ i ][ j ] , dp[ i ][ k ]+dp[ k ][ j ]+cost[ i ][ k ]+cost[ k ][ j ]); 如果j-i<=2 显然花费为0,所以答案微dp[ 0 ][ n-1]。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=305;
 4 const int inf=0x3f3f3f3f;
 5 int n,tot,dp[N][N],cost[N][N],mod;
 6 struct point
 7 {
 8     int x,y;
 9     point(int _x=0,int _y=0){x=_x; y=_y;}
10     point operator -(const point &rhs)const
11     {
12         return point(x-rhs.x,y-rhs.y);
13     }
14 }p[N],cp[N];
15 typedef point vec;
16 int cross(const vec &a,const vec &b)
17 {
18     return (a.x*b.y)-(a.y*b.x);
19 }
20 int dis(point a,point b)
21 {
22     return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
23 }
24 bool cmp(const point &a,const point &b)
25 {
26     int z=cross(a-p[0],b-p[0]);
27     if(z>0||(z==0 && dis(p[0],a)<dis(p[0],b)))
28         return 1;
29     else return 0;
30 }
31 void get_cp()
32 {
33     int k=0; tot=0;
34     for(int i=0;i<n;i++)
35         if(p[i].y<p[k].y || p[i].y==p[k].y && p[i].x<p[k].x) k=i;
36     swap(p[0],p[k]);
37     sort(p+1,p+n,cmp);
38     tot=2,cp[0]=p[0];cp[1]=p[1];
39     for(int i=2;i<n;i++)
40     {
41         while(tot>1 && cross(cp[tot-2]-cp[tot-1],p[i]-cp[tot-1])>0) tot--;
42         cp[tot++]=p[i];
43     }
44 }
45 void init()
46 {
47     memset(dp,-1,sizeof(dp));
48     memset(cost,0,sizeof(cost));
49 }
50 int solve(int l,int r)
51 {
52     if(dp[l][r]!=-1) return dp[l][r];
53     if(r-l<=2) return 0;
54     dp[l][r]=inf;
55     for(int k=l+1;k<=r-1;k++)
56         dp[l][r]=min(solve(l,k)+solve(k,r)+cost[l][k]+cost[k][r],dp[l][r]);
57     return dp[l][r];
58 }
59 int main()
60 {
61     while(scanf("%d%d",&n,&mod)!=EOF)
62     {
63         for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
64         get_cp();
65         if(tot<n)
66         {
67             puts("I can't cut.");
68             continue;
69         }
70         init();
71         for(int i=0;i<n;i++)
72             for(int j=i+2;j<n;j++)
73                 cost[i][j]=cost[j][i]=abs(cp[i].x+cp[j].x)*abs(cp[i].y+cp[j].y)%mod;
74 
75         printf("%d\n",solve(0,n-1));
76     }
77 
78     return 0;
79 }

 

转载于:https://www.cnblogs.com/CJLHY/p/8351294.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值