您的位置:首页 > 其它

uva 10558(dp)

2015-01-06 21:38 477 查看
题意:一个100*100矩阵上有n个点,给出n个点的坐标,然后划了m条竖线,和m条竖线的坐标,然后问如果要切A条线,必须切1和100这两条线,问怎样切横线可以让区域最多,区域必须是有点存在的,边界上的点属于点右上区域。

题解:想不出来,参考网上的人的题解,通过初始化用了个数组s[i][j]表示从第i条横线到第j条横线有多少个区域,然后就可以普通的dp,f[i][j]表示从第i条线到最后且还剩j条横线需要切割最多切多少个区域出来,状态转移方程:f[i][j] = max{f]i][j],f[k][j - 1] + s[i][k]}。然后用path[i][j]存剩余100-i条横线剩余j次切割要切在哪条线上,根据path[i][j]递归输出路径。

#include <stdio.h>
#include <string.h>
const int N = 105;
int n, m, A;
int c
, g

, exi

, d

, s

, f

, path

;

void init() {
for (int i = 1; i < m; i++) {
for (int j = 1; j < 100; j++) {
exi[j][i] = d[j][i] = 0;
for (int k = c[i]; k < c[i + 1]; k++)
if (g[j][k]) {
exi[j][i] = 1;
break;
}
d[j][i] = exi[j][i] + d[j - 1][i];
}
}
for (int i = 1; i < 100; i++) {
for (int j = i + 1; j <= 100; j++) {
s[i][j] = 0;
for (int k = 1; k < m; k++)
if (d[j - 1][k] - d[i][k] + exi[i][k])
s[i][j]++;
}
}
}

int dp(int cur, int p) {
if (f[cur][p] != -1)
return f[cur][p];
if (p == 0)
return f[cur][p] = s[cur][100];
f[cur][p] = 0;
for (int i = cur + 1; i < 100; i++) {
if (p <= 100 - i) {
int temp = dp(i, p - 1);
if (f[cur][p] < temp + s[cur][i]) {
f[cur][p] = temp + s[cur][i];
path[cur][p] = i;
}
}
}
return f[cur][p];
}

void print_path(int cur, int p) {
if (p == 0)
return;
printf(" %d", path[cur][p]);
print_path(path[cur][p], p - 1);
}

int main() {
while (scanf("%d", &n) && n != -1) {
memset(f, -1, sizeof(f));
memset(g, 0, sizeof(g));
int a, b;
for (int i = 0; i < n; i++) {
scanf("%d%d", &a, &b);
g[b][a] = 1;
}
scanf("%d", &m);
for (int i = 1; i <= m; i++)
scanf("%d", &c[i]);
scanf("%d", &A);
init();
dp(1, A - 2);
printf("%d 1", A);
print_path(1, A - 2);
printf(" 100\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  uva dp