ZOJ 3735 Cake(区间DP,最优三角剖分)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4472
开始做下区间DP的题目了。
题解可以参照大牛博客:http://blog.csdn.net/woshi250hua/article/details/7824433
这题很经典,主要是思路:
两种写法写的,一种是DP,一种是记忆化搜索。
DP一定要注意循环的顺序。
代码一:
//============================================================================ // Name : ZOJ.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <math.h> using namespace std; const int MAXN=310; const int INF=0x3f3f3f3f; //二维凸包模板 struct point { int x,y; }; point list[MAXN]; int stack[MAXN],top; int cross(point p0,point p1,point p2) { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(point p1,point p2) { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(point p1,point p2) { int tmp=cross(list[0],p1,p2); if(tmp>0)return true; else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2))return true; else return false; } void init(int n) { int i,k; point p0; scanf("%d%d",&list[0].x,&list[0].y); p0.x=list[0].x; p0.y=list[0].y; k=0; for(i=1;i<n;i++) { scanf("%d%d",&list[i].x,&list[i].y); if((p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x))) { p0.x=list[i].x; p0.y=list[i].y; k=i; } } list[k]=list[0]; list[0]=p0; sort(list+1,list+n,cmp); } void graham(int n) { int i; if(n==1){top=0;stack[0]=0;} if(n==2) { top=1; stack[0]=0; stack[1]=1; } if(n>2) { for(i=0;i<=1;i++)stack[i]=i; top=1; for(i=2;i<n;i++) { while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0)top--; top++; stack[top]=i; } } } int n,m; int cost[MAXN][MAXN]; int calc(point p1,point p2)//计算题目定义的cost { return abs(p1.x+p2.x)*abs(p1.y+p2.y)%m; } int dp[MAXN][MAXN]; int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&m)==2) { init(n); graham(n); if(top!=n-1) { printf("I can't cut.\n"); continue; } memset(cost,0,sizeof(cost)); for(int i=0;i<n;i++) for(int j=i+2;j<n;j++) cost[i][j]=cost[j][i]=calc(list[i],list[j]); for(int i=0;i<n;i++) { for(int j=i;j<n;j++)dp[i][j]=INF; dp[i][(i+1)%n]=0; } 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]+cost[i][k]+cost[k][j]); printf("%d\n",dp[0][n-1]); } return 0; }
代码二:
//============================================================================ // Name : ZOJ.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <math.h> using namespace std; const int MAXN=310; const int INF=0x3f3f3f3f; //二维凸包模板 struct point { int x,y; }; point list[MAXN]; int stack[MAXN],top; int cross(point p0,point p1,point p2) { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(point p1,point p2) { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(point p1,point p2) { int tmp=cross(list[0],p1,p2); if(tmp>0)return true; else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2))return true; else return false; } void init(int n) { int i,k; point p0; scanf("%d%d",&list[0].x,&list[0].y); p0.x=list[0].x; p0.y=list[0].y; k=0; for(i=1;i<n;i++) { scanf("%d%d",&list[i].x,&list[i].y); if((p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x))) { p0.x=list[i].x; p0.y=list[i].y; k=i; } } list[k]=list[0]; list[0]=p0; sort(list+1,list+n,cmp); } void graham(int n) { int i; if(n==1){top=0;stack[0]=0;} if(n==2) { top=1; stack[0]=0; stack[1]=1; } if(n>2) { for(i=0;i<=1;i++)stack[i]=i; top=1; for(i=2;i<n;i++) { while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0)top--; top++; stack[top]=i; } } } int n,m; int cost[MAXN][MAXN]; int calc(point p1,point p2)//计算题目定义的cost { return abs(p1.x+p2.x)*abs(p1.y+p2.y)%m; } int dp[MAXN][MAXN]; int solve(int s,int t) { if(dp[s][t]!=INF)return dp[s][t]; int ans=INF; for(int i=s+1;i<t;i++) ans=min(ans,solve(s,i)+solve(i,t)+cost[s][i]+cost[i][t]); return dp[s][t]=ans; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&m)==2) { init(n); graham(n); if(top!=n-1) { printf("I can't cut.\n"); continue; } memset(cost,0,sizeof(cost)); for(int i=0;i<n;i++) for(int j=i+2;j<n;j++) cost[i][j]=cost[j][i]=calc(list[i],list[j]); for(int i=0;i<n;i++) { for(int j=i;j<n;j++)dp[i][j]=INF; dp[i][(i+1)%n]=0; } printf("%d\n",solve(0,n-1)); } return 0; }
人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想