题意:一个棋盘,横竖线都是从1到100标号(竖线从左到右标,横线从下到上标),输入n表示有n个被标记的格子,是给出这个格子的左下角坐标,然后输入m,在输入m个数,表示在这些竖线的地方切开棋盘(其实只切了m-2刀,因为2刀必须是1和100,相当于没有),然后输入A,表示你要在横上上切A刀(其实也只是A-2刀,因为2刀必须在横线的1和100)。那么就可以把棋盘很多个大小不一的方块(矩形),只要这些方块中有被标记的小格子(1个或多个),那么这个方块就是一个选区,我们是要使到选区的个数最多
思路:题目实在难看懂,想法是看这个博客点击打开链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 110;
int N, S, A;
int street[MAXN], g[MAXN][MAXN], e[MAXN][MAXN], f[MAXN][MAXN], sum[MAXN][MAXN];
int vis[MAXN][MAXN], d[MAXN][MAXN], path[MAXN][MAXN];
void init() {
memset(e, 0, sizeof(e));
memset(f, 0, sizeof(f));
memset(sum, 0, sizeof(sum));
for (int k = 1; k < S; k++)
for (int i = 1; i < 100; i++) {
for (int j = street[k]; j < street[k + 1]; j++)
if (g[i][j] == 1) {
e[i][k]=1;
break;
}
f[i][k] = e[i][k];
f[i][k] += f[i-1][k];
}
for (int i = 1; i < 100; i++)
for (int j = i + 1; j <= 100; j++)
for (int k = 1; k < S; k++)
if (f[j - 1][k] - f[i][k] + e[i][k])
sum[i][j]++;
}
int dp(int i, int j) {
if (vis[i][j])
return d[i][j];
vis[i][j] = 1;
if (j == 0)
return d[i][j] = sum[i][100];
for (int k = i + 1; k < 100; k++) {
if (100 - k - 1 < j - 1)
break;
if (d[i][j] < dp(k, j - 1) + sum[i][k]) {
d[i][j] = dp(k, j - 1) + sum[i][k];
path[i][j] = k;
}
}
return d[i][j];
}
void outPut(int i, int j) {
if (j <= 0)
return;
printf(" %d", path[i][j]);
outPut(path[i][j], j - 1);
}
int main() {
while (scanf("%d", &N) && N != -1) {
int x, y;
memset(g, 0, sizeof(g));
for (int i = 1; i <= N; i++) {
scanf("%d %d", &x, &y);
g[y][x] = 1;
}
scanf("%d", &S);
for (int i = 1; i <= S; i++)
scanf("%d", &street[i]);
scanf("%d", &A);
init();
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
dp(1, A - 2);
printf("%d", A);
printf(" 1");
outPut(1, A - 2);
printf(" 100\n");
}
return 0;
}