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 ≤ 101 ≤ m ≤ 10
1 ≤ k ≤ 50
Input
接下来 n 行:每行 m 个正整数,范围在[1,10],第 i 行第 j 个数表示当前桌面那张矩形纸里边第 i 行第 j 个格子里的数字。
Output
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 |
18 | 26612 |
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];
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];
}
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;
}