现在的位置: 首页 > 综合 > 正文

ZOJ 3735 Cake(区间DP,最优三角剖分)

2012年09月01日 ⁄ 综合 ⁄ 共 4200字 ⁄ 字号 评论关闭

题目链接: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;
}

 

 

 

【上篇】
【下篇】

抱歉!评论已关闭.