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;

}

 

 

 

你可能感兴趣的:(ZOJ)