题目超链接
题意
中文题目没啥好说的
首先得知道这是一个dp题,然后再求解,至于怎么知道,还是写题少,菜鸟的悲伤,呜呜呜。
知道是dp后,接下来就是分析了,对于左边分析,肯定是先扩张,然后可能会缩减,而且一旦缩减就不会在扩张了,这样是吧为了保证图形是凸型,
对于右边也是一样的,然后就是看怎么保证是扩张还是缩减了,那么就要知道前一行的某个状态的l到r的状态,然后在本状态再根据是扩张还是缩减
来定义本状态的l和r的值。所以就有下面几个需要维护的:到第几行了,有多少个格子了,本状态的l,本状态的r,左边的扩张还是缩减,右边的扩张还是缩减。
然后就是状态转移方程了
#include <algorithm>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <unordered_map>
#include <vector>
#define ll long long int
#define ms(a, b) memset(a, b, sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define ull unsigned long long
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define endl "\n"
#define bug cout << "----acac----" << endl;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
const int maxn = 5e5 + 10;
const int maxm = 1e3 + 50;
const double eps = 1e-8;
const ll inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1);
const ll mod = 1e9 + 7;
int n, m, k;
int a[20][20];
int dp[16][16 * 16][16][16][2][2];
struct node
{
int i, j, l, r, x, y;
} pre[16][16*16][16][16][2][2];
void print(node A)
{
if(A.j==0)
return;
print(pre[A.i][A.j][A.l][A.r][A.x][A.y]);
for (int i = A.l; i <= A.r;i++)
{
cout << A.i << " " << i << endl;
}
}
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= n;i++)
{
for (int j = 1; j <= m;j++)
{
cin >> a[i][j];
a[i][j] += a[i][j - 1];
}
}
int ans = 0;
node t;
for (int i = 1; i <= n;i++)
{
for (int j = 1; j <= k;j++)
{
for (int l = 1; l <= m;l++)
{
for (int r = l; r <= m;r++)
{
if(j<(r-l+1))
continue;
//左边扩张,右边也扩张;
for (int l1 = l; l1 <= r;l1++)
{
for (int r1 = l1; r1 <= r;r1++)
{
int &u = dp[i][j][l][r][0][0];
int v = dp[i - 1][j - (r - l + 1)][l1][r1][0][0] + a[i][r] - a[i][l - 1];
if(u<v)
{
pre[i][j][l][r][0][0] = {i - 1, j - (r - l + 1), l1, r1, 0, 0};
u = v;
}
}
}
//左边扩张,右边收缩
for (int l1 = l; l1 <= r;l1++)
{
for (int r1 = r; r1 <= m;r1++)
{
for (int y = 0; y <= 1;y++)
{
int &u = dp[i][j][l][r][0][1];
int v = dp[i - 1][j - (r - l + 1)][l1][r1][0][y] + a[i][r] - a[i][l - 1];
if(u<v)
{
pre[i][j][l][r][0][1] = {i - 1, j - (r - l + 1), l1, r1, 0, y};
u = v;
}
}
}
}
//左边收缩,右边扩张
for (int l1 = 1; l1 <= l;l1++)
{
for (int r1 = l; r1 <= r;r1++)
{
for (int x = 0; x <= 1;x++)
{
int &u = dp[i][j][l][r][1][0];
int v = dp[i - 1][j - (r - l + 1)][l1][r1][x][0] + a[i][r] - a[i][l - 1];
if(u<v)
{
pre[i][j][l][r][1][0] = {i - 1, j - (r - l + 1), l1, r1, x, 0};
u = v;
}
}
}
}
//左边收缩,右边也收缩
for (int l1 = 1; l1 <= l;l1++)
{
for (int r1 = r; r1 <= m;r1++)
{
for (int x = 0; x <= 1;x++)
{
for (int y = 0; y <= 1;y++)
{
int &u = dp[i][j][l][r][1][1];
int v = dp[i - 1][j - (r - l + 1)][l1][r1][x][y] + a[i][r] - a[i][l - 1];
if(u<v)
{
pre[i][j][l][r][1][1] = {i - 1, j - (r - l + 1), l1, r1, x, y};
u = v;
}
}
}
}
}
if(j==k)
{
for (int x = 0; x <= 1;x++)
{
for (int y = 0; y <= 1;y++)
{
if(ans<dp[i][j][l][r][x][y])
{
ans = dp[i][j][l][r][x][y];
t = {i, j, l, r, x, y};
}
}
}
}
}
}
}
}
cout << "Oil : " << ans << endl;
print(t);
return 0;
}