UESTC OJ 88 Fold The Paper(状态压缩)

题目链接:http://acm.uestc.edu.cn/#/problem/show/88


You have a rectangular piece of paper that is divided into 1×1 cells, each of which has an integer value.

You want to perform a sequence of folds on the paper, where you may fold anywhere along an axis that is in between two rows or columns of the paper. After performing all the folds you want, the overlapping cells will be considered as a single cell, whose value is the sum of the individual cells.

You want the biggest number in the resulting piece of paper to be as large as possible, what is the biggest number you can get ?

Input

First line of the input is a single integer T(1T10), indicating there are T test cases. For each test case, the first line contains two integers, N and M (1N20,1M500), indicating the length and width of the paper. Then N lines followed, each line contains M integers xi(104xi104), indicating the numbers in the original piece of paper.

Output

For each case,output Case #t: ret in a single line, where t indicating the case number between 1 and T, and ret is the biggest number you can get in the resulting piece of paper.

Sample input and output

Sample InputSample Output
2
2 2
1 -2
3 -4
2 5
1 -2 -3 4 -5
6 -7 -8 9 -10
Case #1: 4
Case #2: 20

Hint

  1. Of course, if you do not fold any cells, the value of each cell is its original value.
  2. Explanation for the 2nd Case in Sample Input

    .*

  3. Note that merging the overlapping cells only happens after all the folds, which means:

    .*


题意:
把一个n*m的矩阵,通过对折的方式,使对折后某一个单元格的值最大,对折后重合的单元格的值相加!
PS:
我们状态压缩每一行折叠的状态!
每次折叠后统计每一列的值!
到最后再利用奇偶性dp出每一列的最大值!
最后和开始不折叠的最大值比较!
注意我们状态压缩的时候需要从1开始压缩!
之前一直wa在后台测试数据的第一个案例,
有这种情况:
1 1
-1
所以我们不能从i = 0 开始压缩!
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
    int t;
    int n, m;
    int a[30][520];
    int cas = 0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int ans = -INF;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j] > ans)
                    ans = a[i][j];
            }
        }
        for(int i = 1; i < (1<<n); i++)//状态压缩行
        {
            int flag = 0;
            int t1 = -1, t2 = -1;//记录前后行位置
            for(int j = 0; j < n; j++)
            {
                if(i & (1<<j))
                {
                    t1 = j;
                    if(t2>=0 && (t1-t2)%2 == 0)//行相差为偶数不行折叠
                    {
                        flag = 1;
                        break;
                    }
                    t2 = t1;
                }
            }
            if(flag)
                continue;

            int sum[520];//每一列的和
            memset(sum,0,sizeof(sum));
            for(int k = 0; k < m; k++)//lie
            {
                for(int h = 0; h < n; h++)//hang
                {
                    if(i & (1<<h))
                        sum[k] += a[h][k];
                }
            }
            int dp[2];
            dp[0] = dp[1] = -INF;
            for(int j = 0; j < m; j++)
            {
                if(j & 1)//奇
                {
                    dp[1] = max(dp[1],sum[j]);
                    dp[1] = max(dp[1],dp[0]+sum[j]);
                }
                else//偶
                {
                    dp[0] = max(dp[0],sum[j]);
                    dp[0] = max(dp[0],dp[1]+sum[j]);
                }
            }
            dp[1] = max(dp[1],dp[0]);
            ans = max(ans,dp[1]);
        }
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}
/*
99
1 1
-1
2 2
1 -2
3 -4
2 5
1 -2 -3 4 -5
6 -7 -8 9 -10
*/






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值