uva 10558 A Brief Gerrymander (dp记忆化搜寻)

uva 10558 A Brief Gerrymander (dp记忆化搜索)

Problem E: A Brief Gerrymander

The evil ruling party, the Liberatives, are redistributing the electoral regions (ridings) in your city, and are nefariously attempting to pack certain opposition-friendly neighborhoods into as few ridings as possible. If this plan succeeds, it will be the end of democracy as we know it! As a card-carrying member of the noble, compassionate Conservals (the main opposition party), you must foil their devious plot and safeguard the future of our country.

Under the new plan, the city will be divided up into a grid of rectangles by selecting certain major streets and avenues as boundaries. All streets and avenues stretch straight across the city, and are numbered starting from the southwest corner of the city. The city is bounded by four roads: 1st Street (west edge), 100th Street (east edge), 1st Avenue (south edge), 100th Avenue (north edge). Clearly these four roads must represent district boundaries; however, only a subset of the streets and avenues in between will divide districts. The Liberatives have already been able to fix the North-South (street) boundaries; however, they have been forced to allow the Conservals to select the East-West (avenue) boundaries.

You know the location of all the opposition-friendly neighborhoods, which vote strongly Conserval. A neighborhood is exactly one block between adjacent streets and avenues. For instance, one neighborhood might lie between 47th and 48th Street and 67th and 68th Avenue. Place the avenue boundaries so that as many ridings as possible contain at least one opposition-friendly neighborhood.

Input consists of multiple cases, each describing a city. The first line will give N, the number of Conserval neighborhoods in the city; the following N lines will contain the street and avenue number of the southwest corner of each neighborhood. The next line will contain S, the number of street boundaries, and the S street numbers that they lie on, in increasing order. The final line will consist of A (at least 2), the number of avenue boundaries you must place. Input will be terminated by a line containing -1.

For each case, output a single line giving A followed by A distinct avenue numbers for the optimal redistriubution, in increasing order. If there are multiple such solutions, any one will do.

Sample Input

2
49 49 
50 50
2 1 100
3
-1

Sample Output

3 1 50 100

题意: 题意实在理解不透啊,,最后还是去看了题解。。。然后后来就几乎参考http://www.cnblogs.com/scau20110726/archive/2012/10/04/2711436.html

思路:这题在预处理的时候,关键求出s[i][j]数组,表示在i到j横线上可以有几个分区。之后就是简单的记忆化搜索了。dp[i][j]表示第i条横线,和还要切j刀,等于只要考虑第i条横线切不切就可以了.

代码:

#include <stdio.h>
#include <string.h>
const int MAXN = 110;
int n, map[MAXN][MAXN], m, cut[MAXN], A;
int only[MAXN][MAXN], f[MAXN][MAXN], s[MAXN][MAXN];
int dp[MAXN][MAXN], path[MAXN][MAXN], vis[MAXN][MAXN];

void init() {
	int a, b, i, j, k;
	memset(dp, 0, sizeof(dp));
	memset(vis, 0, sizeof(vis));
	memset(map, 0, sizeof(map));
	for (i = 1; i <= n; i ++) {
		scanf("%d%d", &a, &b);
		map[b][a] = 1;
	}
	scanf("%d", &m);
	for (i = 1; i <= m; i ++) {
		scanf("%d", &cut[i]);
	}
	scanf("%d", &A);
	for (k = 1; k < m; k ++)
		for (i = 1; i < 100; i ++) {
			only[i][k] = f[i][k] = 0;
			for(j = cut[k]; j < cut[k+1]; j ++) {
				if (map[i][j] == 1) { 
					only[i][k] = 1; 
					break; 
				}
			}
			f[i][k] = only[i][k];
			f[i][k] += f[i-1][k];
		}
		for (i = 1; i < 100; i ++)
            for (j = i + 1; j <= 100; j ++)
            {
                s[i][j] = 0;
                for (k = 1; k < m; k ++)
                    if (f[j - 1][k] - f[i][k] + only[i][k])
                        s[i][j] ++;
            }
}

int DP(int i, int j) {
	int k, ans;
	if (vis[i][j])
		return dp[i][j];
	vis[i][j] = 1;
	if (j == 0) {
		return dp[i][j] = s[i][100];
	}
	for (k = i + 1; k < 100; k ++) {
		if (100 - k - 1 < j - 1)
			break;
		ans = DP(k, j - 1);
		if (ans + s[i][k] > dp[i][j]) {
			dp[i][j] = ans + s[i][k];
			path[i][j] = k;
		}
	}
	return dp[i][j];
}

void print(int i, int j) {
	if (j <= 0) return;
	printf(" %d", path[i][j]);
	print(path[i][j], j - 1);
}

int main() {
	while (~scanf("%d", &n) && n != -1) {
		init();
		DP(1,  A - 2);
		printf("%d", A);
		printf(" 1");
		print(1, A - 2);
		printf(" 100\n");
	}
	return 0;
}