Codeforces Round #531 (Div. 3) F. Elongated Matrix (状态压缩dp)

题目链接

题意:
给出一个n * m矩阵,可以交换任意的两行,不能交换列,得到一个序列a[0][0], a[1][0], … a[0][1], a[1][1], …a[0][2], a[1][2], …以此类推,以Si代表这个序列的第i个元素,令k = min|Si - Si+1|,要求最终得到的k最大。

思路:
首先呢,看到题目中给的n才16,就该考虑往状态压缩方面去想一想了,那么接下来思考,我们的状态表示的是什么?很显然,表示的是某一行的选(对应二进制位为1)或者说不选(这不是废话吗。。。也就只有n能用二进制来枚举了,其他的数都太大了)。OK,下来我们考虑怎么进行状态的转移,设dp[status][pos]代表在状态status时,以第pos个数结尾的情况最大的k。那么状态转移方程就是:
dp[status][pos] = max(dp[status][pos], min(dp[status0][mid], dif[mid][pos])
来详细解释一下这个方程,status0代表上一个,算是一个中转状态(不包含pos,也就是第pos个还没有选),mid代表一个中转点,以此来推出当前的dp[status][pos]。而dif数组则代表第mid行和第pos行同一列的差值,这个就需要预处理了。

整个代码的思路就是:
1.枚举开始的行
2.初始化,计算dp数组
3.枚举结束的行

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

const int maxn = 1e4 + 100;

int n, m;
int a[20][maxn], dif[20][20], dif_next[20][20];
int dp[7 * maxn][20];

int main()
{
    //freopen("in.txt", "r", stdin);
    cin >> n >> m;
    for(int i = 0; i < n; ++ i) {
        for(int j = 0; j < m; ++ j) {
            scanf("%d", &a[i][j]);
        }
    }
    for(int i = 0; i < n; ++ i) {
        for(int j = i + 1; j < n; ++ j) {
            int mins = 0x3f3f3f3f;
            for(int u = 0; u < m; ++ u) {
                mins = min(mins, abs(a[i][u] - a[j][u]));
            }
            dif[i][j] = dif[j][i] = mins;
        }   
    }
    int ans = 0;
    for(int st = 0; st < n; ++ st)  //枚举起点
    {
        for(int i = 0; i < (1 << n); ++ i)     //初始化
            fill_n(dp[i], n, 0);
        dp[1 << st][st] = 0x3f3f3f3f;
        for(int status = 1; status < (1 << n); ++ status)   //枚举状态
        {
            for(int mid = 0; mid < n; ++ mid)
            {
                if(dp[status][mid])     //枚举中转点
                {
                    for(int pos = 0; pos < n; ++ pos)   //枚举要求解的点
                    {
                        if(!(status & (1 << pos)))   //这个点不在之前的状态中才能求解
                        {
                            dp[status|(1<<pos)][pos] = max(dp[status|(1<<pos)][pos], min(dp[status][mid], dif[mid][pos]));
                        }
                    }
                }
            }
        }
        for(int en = 0; en < n; ++ en)
        {
            int k = dp[(1 << n) - 1][en];
            for(int i = 0; i + 1 < m; ++ i)
            {
                k = min(k, abs(a[en][i] - a[st][i + 1]));
            }
            ans = max(ans, k);
        }
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/86478591
今日推荐