Papercut

Time Limit: 1000MS  Memory Limit: 65536K
Total Submissions: 266  Accepted: 71

Description

现在桌面上有一张矩形纸,上边有n ×m 个格子,每个格子有一个数字。每张矩形纸可以算出一个数值F,F 是由纸张里任意两个不同的格子里的数字相乘之和。如果该纸只有一个格子,那么F =0。

剪纸规则是:
1、沿格子边缘一直剪成两个矩形纸,每张纸里必须有数字。
2、每次剪纸在桌面上任意选一张矩形纸,进行1操作,再把剪出来的两张纸放到桌面。

现在你可以对桌面上的纸最多剪k次,问最后桌面上所有矩形纸的F值之和最小是多少?

1 ≤ n ≤ 10
1 ≤ m ≤ 10
1 ≤ k ≤ 50

Input

第一行:3个整数 n , m , k
接下来 n 行:每行 m 个正整数,范围在[1,10],第 i 行第 j 个数表示当前桌面那张矩形纸里边第 i 行第 j 个格子里的数字。

Output

一个整数。代表最小 F 值和。

Sample Input

Sample Input #1 Sample Input #2
4 4 4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
 
10 10 5
4 2 3 5 6 10 1 6 5 8
3 6 9 1 7 10 7 10 8 1
7 8 3 3 2 5 9 9 8 2
5 5 9 9 3 10 2 9 10 2
1 1 6 7 6 8 3 9 6 8
7 1 2 5 3 2 3 7 8 10
10 9 8 9 7 8 10 7 3 9
6 3 6 2 1 7 10 6 7 2
2 4 8 4 5 9 10 5 9 10
7 4 3 2 4 9 9 9 8 1

Sample Output

Sample Output #1 Sample Output #2
1826612

Hint

Sample 1说明: 按照下面方式剪纸4次
1   1   1   1
-------------
1 | 1 | 1 | 1
   |    |    |
1 | 1 | 1 | 1
   |    |    |
1 | 1 | 1 | 1
得到6+3+3+3+3=18

 

----------------------------------------------------------------------------------------------

前面提到过之前比赛的时候做这道题无限WA,现在终于得到oj的认证,终于肯给我一个Accept了。

之前没看清楚题意,以为跟棋盘分割是一样的,其实是有点不同的,棋盘分割只能选择切完之后的其中一个子矩阵来切,而这道PaperCut是两边都可以切。

还有一个关键字眼就是:“最多”能切k次,也就是说,选择一个切k次以内得到的最小值。

其它的也就没什么好讲了。

在动态规划上迈出了艰难的一步……

----------------------------------------------------------------------------------------------

 

源码如下,仅供参考:

 

==============================================================================================

 

#include<stdio.h>
#include<string.h>
int pap[20][20];
int s[20][20][20][20];
int t[20][20][20][20][55];
//i1,j1表示矩形左上角,i2,j2表示矩形右上角。计算这个矩形的值,内部无切割。值存在s[20][20][20][20]内。
int cal(int i1,int j1,int i2,int j2)
{
    if(s[i1][j1][i2][j2]>=0)
        return s[i1][j1][i2][j2];
    if(i1==i2 && j1==j2)
    {
        s[i1][j1][i2][j2]=0;
        return s[i1][j1][i2][j2];
    }
    int i,j,k,l,sum=0;
    for(i=i1;i<=i2;i++)
    {
        for(j=j1;j<=j2;j++)
        {
            for(l=j+1;l<=j2;l++)
                sum+=pap[i][j]*pap[i][l];
            for(k=i+1;k<=i2;k++)
            {
                for(l=j1;l<=j2;l++)
                {
                    sum+=pap[i][j]*pap[k][l];
                }
            }
        }
    }
    s[i1][j1][i2][j2]=sum;
    return s[i1][j1][i2][j2];

}

//计算这个矩形内切K刀的最小值。存在int t[20][20][20][20][55]内,55是k刀。
int cut(int i1,int j1,int i2,int j2,int k)
{
    if(i1==i2 && j1==j2)
    {
        t[i1][j1][i2][j2][k]=cal(i1,j1,i2,j2);
        return t[i1][j1][i2][j2][k];
    }
    if(k==0)
    {
        t[i1][j1][i2][j2][k]=cal(i1,j1,i2,j2);
        return t[i1][j1][i2][j2][k];
    }
    if(t[i1][j1][i2][j2][k]>=0)
        return t[i1][j1][i2][j2][k];
    int i,j,p;
    int temp=0,min=2140000000;
    for(i=i1;i<i2;i++)
    {
        for(p=0;p<k;p++)
        {
            temp=cut(i1,j1,i,j2,p)+cut(i+1,j1,i2,j2,k-p-1);
            if(temp<min && temp>=0)
                min=temp;
        }
    }
    for(j=j1;j<j2;j++)
    {
        for(p=0;p<k;p++)
        {
            temp=cut(i1,j1,i2,j,p)+cut(i1,j+1,i2,j2,k-p-1);
            if(temp<min && temp>=0)
                min=temp;
        }
    }
    t[i1][j1][i2][j2][k]=min;
    return t[i1][j1][i2][j2][k];

}
int main()
{
    //freopen("1.txt","r",stdin);
    int n,m,k;
    int i,j;
    memset(pap,0,sizeof(pap));
    memset(s,-1,sizeof(s));
    memset(t,-1,sizeof(t));
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            scanf("%d",&pap[i][j]);
        }
    }
    int temp=0,min=2140000000;
    for(i=1;i<=k;i++)
    {
        temp=cut(1,1,n,m,k);
        if(temp<min)
            min=temp;
    }
    printf("%d/n",min);


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值