[BALTIC 2008] Grid

本文介绍了一种解决二维切割问题的优化算法,通过DFS枚举横切方案,结合二分搜索和贪心策略,实现了O(2^N*N^2logN)的时间复杂度。文章详细解析了算法流程,包括状态压缩、前缀和计算、二分查找最优解等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=1169

[算法]

        首先DFS枚举出横着切的

        然后二分 + 贪心即可

        时间复杂度 : O(2 ^ N * N ^ 2logN)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define N 20
const int inf = 2e9;

int n , m , r , s , cnt;
ll ans;
ll a[N][N] , sum[N][N] , dp[N][N] , b[N];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline int calc(int x)
{
        int ret = 0;
        for (int i = x; i; i -= i & (-i)) 
                ++ret;
        return ret;
}
inline ll calc_sum(int X1 , int Y1 , int X2 , int Y2) {
        return sum[X2][Y2] - sum[X1 - 1][Y2] - sum[X2][Y1 - 1] + sum[X1 - 1][Y1 - 1];
}
inline bool check(ll limit) {
        int pre = 1 , cut = 0;
        for (int i = 1; i <= m; ++i) {
                for (int j = 1; j <= cnt; ++j) {
                        if (calc_sum(b[j - 1] + 1 , i , b[j] , i) > limit)
                                return false;
                }
        }
        for (int i = 1; i <= m; ++i) {
                ll value = 0;
                for (int j = 1; j <= cnt; ++j) {    
                        if (calc_sum(b[j - 1] + 1 , pre , b[j] , i) <= limit)
                                continue; 
                        else {
                                pre = i;
                                ++cut;                                
                        }
                }
        }
        return cut <= s;
}
inline ll getans(ll S) {
        cnt = 0;
        for (int i = 0; i < n; ++i)
                if (S & (1 << i)) b[++cnt] = i + 1;
        b[++cnt] = n;
        ll l = 0 , r = ans , ret = inf;
        while (l <= r) {
                int mid = (l + r) >> 1;
                if (check(mid))
                {
                        ret = mid;
                        r = mid - 1;        
                } else l = mid + 1;
        } 
        return ret;
}

int main() {
        
        read(n); read(m); read(r); read(s);
        for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                        read(a[i][j]);
                        sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
                }
        }
        ans = sum[n][m];
        for (int i = 0; i < (1 << n); ++i)
        {
                if (calc(i) == r)
                        chkmin(ans , getans(i));
        }
        printf("%lld\n" , ans);
        
        return 0;
    
}

 

转载于:https://www.cnblogs.com/evenbao/p/10778113.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值