UVA - 10558A Brief Gerrymander(递推)

题目大意:UVA - 10558A Brief Gerrymander(递推)

题目大意:给定一个100 * 100 的矩形,现在要求将这个区域划分,竖着的线已经给你划分好了,现在要求你在这个区域内再添加A个横着的线,1 100 这两条是一定要的,问怎样选择横着的线,能够使得选举区间最多。选举区间的条件:内部没有横竖线,并且有一个点在区间内部。注意:边界上的点也是算在内的,但是要防止重复计算到选区内。

解题思路:这题题意都不是那么好理解了,然后写起来复杂度也是很大的。参考了别人的题解:首先:dp[i][j]代表第i根横线的序号是j的时候,有多少个选区。S【i】【j】代表:第i根横线到第j根横线之间在已知竖线的情况下有多少个选区。注意这里因为要算边界的点,所以i到j是左闭右开【i,j)(包括i这线上的点,但是不包括j这条横线上的点)。dp【【i】【j】 =Max ( dp【i - 1】【k】 + s【k】【j】));

所以先要预处理出S【i】【j】:处理的时候也需要找个策略不然复杂度也是很高。用G【i】【j】【k】代表第i条横线到第j条横线和第i - 1竖线和第i条竖线是否是选取区。G【i】【j】【k】 |= G[i][j - 1][k];

G[i][j][k] |= t【j】【k】(第j - 1条直线上是否有点在K-1和k竖线之间,注意这里竖线的边界点也要计算,并且要防止重复。同理:【K -1 ,K)。

代码:

#include <cstdio>
#include <cstring>

const int N = 105;

int n, m;
int s[N][N];
int t[N][N];
int dp[N][N];
int p[N][N];
int street[N];
int G[N][N][N];
int path[N][N];

int Max (const int a, const int b) { return a > b ? a: b; }

void init () {

	memset (t, 0, sizeof (t));
	for (int i = 1; i <= 100; i++) {
		for (int j = 1; j < m; j++) {
			int k;
			for (k = street[j - 1]; k < street[j]; k++)
				if (p[i - 1][k])
					break;
			if (k != street[j])
				t[i][j] = 1;
		}
	}

	memset (G, 0, sizeof (G));
	memset (s, 0, sizeof (s));
	for (int i = 1; i < 100; i++) {
		for (int j = 1; j + i <= 100; j++) {

			for (int k = 1; k < m; k++)
				G[j][j + i][k] |= G[j][j + i - 1][k];

			for (int k = 1; k < m; k++)
				G[j][j + i][k] |= t[j + i][k];
			for (int k = 1; k < m; k++)
				if (G[j][j + i][k])
					s[j][j + i]++;
		}
	}

}

void printf_ans (int A, int j) {

	if (path[A][j] == -1)
		return;
	printf_ans (A - 1, path[A][j]);
	printf (" %d", path[A][j]);
}

int main () {

	int x, y, A;
	while (scanf ("%d", &n) && n != -1) {

		memset (p, 0, sizeof (p));
		for (int i = 0; i < n; i++) {

			scanf ("%d%d", &x, &y);
			p[y][x] = 1;
		}
		scanf ("%d", &m);
		for (int i = 0; i < m; i++)
			scanf ("%d", &street[i]);
		scanf ("%d", &A);

		init ();

		dp[1][1] = 0;
		path[1][1] = -1;
		for (int i = 2; i <= A; i++) {
			for (int j = i; j <= 100; j++) {

				dp[i][j] = 0;
				if (i == 2) {
					dp[i][j] = Max (dp[i][j] , dp[1][1] + s[1][j]);
					path[i][j] = 1;
				} else {

					for (int k = 2; k < j; k++) {
						if (dp[i - 1][k] + s[k][j] >= dp[i][j])
							path[i][j] = k;
						dp[i][j] = Max (dp[i][j] , dp[i - 1][k] + s[k][j]);
					}
				}
			}
		}

//		printf ("%d\n", t[50][1]);
		printf ("%d", A);
		printf_ans(A, 100);
		printf (" 100\n");

	}
	return 0;
}

UVA - 10558A Brief Gerrymander(递推)

时间: 2024-11-05 02:34:50

UVA - 10558A Brief Gerrymander(递推)的相关文章

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

题目链接:uva 1478 - Delta Wave 题目大意:对于每个位置来说,可以向上,水平,向下,坐标不能位负,每次上下移动最多为1, 给定n问说有多少种不同的图.结果对10100取模. 解题思路:因为最后都要落回y=0的位置,所以上升的次数和下降的次数是相同的,并且上升下降的关系满足出栈入栈的关系.即卡特兰数. 所以每次枚举i,表示有i个上升,i个下降,用组合数学枚举出位置,然后累加求和. C(2?in)?f(i)=C(2?i?2n)?f(i?1)?(n?2?i+1)?(n?2?i+2)

【UVA】12034-Race(递推,组合数打表)

递推公式,假设第一名有i个人并列,那么: f[n] = C(n,i) * f[n - i]; 打出1 ~ 1000的所有组合数,之后记忆化搜索,需要打表. 14026995 12034 Race Accepted C++ 0.032 2014-08-12 11:47:47 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector&g

UVA - 620Cellular Structure(递推)

题目:UVA - 620Cellular Structure(递推) 题目大意:只能给出三种细胞的增殖方式,然后给出最后细胞的增殖结果,最后问你这是由哪一种增殖方式得到的.如果可以由多种增殖方式得到,就输出题目中列出来的增殖方式靠前的那种. 解题思路:也是递推,细胞长度长的可以由细胞长度短的推得,并且这里第一种只能是长度为1的细胞才有可能,所以判断的时候可以3个判断,看能否与上面的增殖结果匹配,可以的话就记录下来,以后的长串就是由这样的短串再加上两个细胞继续往后推. 例如: BAABA 将A变为

uva 1485 - Permutation Counting(递推)

题目链接:uva 1485 - Permutation Counting 题目大意:给定n和k,要求求一个由1~n组成的序列,要求满足ai>i的i刚好有k个的序列种数. 解题思路:dp[j][i]表示长度为i,j个位置满足的情况. dp[j+1][i]+=dp[j][i]?(j+1); 1, (3), (4), 2: 括号位置代表ai>i,既满足位置,此时i = 4, j = 2. -> 1, (3), (4), 2, 5 1 种,在最后追加 -> 1, (5), (4), 2,

UVA - 10003Cutting Sticks(递推)

题目:UVA - 10003Cutting Sticks(递推) 题目大意:给根木棍长度l,现在要锯这根木棍,给出n个锯点,求怎样锯才能使得开销最小.例如 长度为10的木棍, 锯点2 4 7,那么如果按照这个顺序 , 首先显示由长度位10的木头先锯了2 ,开销就加10,然后锯完现在有[0,2]和[2,10]长度分别为2 ,8的木棍,现在要在4这个位置锯木头,就是在长度为8的木头上锯4这个位置,这样就加上8,然后又有长度为[2,4][4,10]的木头,最后要锯7的话,就需要开销加上6.所以开销就是

UVA 11021 - Tribles(概率递推)

UVA 11021 - Tribles 题目链接 题意:k个毛球,每个毛球死后会产生i个毛球的概率为pi,问m天后,所有毛球都死亡的概率 思路:f[i]为一个毛球第i天死亡的概率,那么 f(i)=p0+p1f(i?1)+p2f(i?1)2+...+pnf(i?1)n 然后k个毛球利用乘法定理,答案为f(m)k 代码: #include <stdio.h> #include <string.h> #include <math.h> const int N = 1005;

UVA 10288 - Coupons(概率递推)

UVA 10288 - Coupons 题目链接 题意:n个张票,每张票取到概率等价,问连续取一定次数后,拥有所有的票的期望 思路:递推,f[i]表示还差i张票的时候期望,那么递推式为 f(i)=f(i)?(n?i)/n+f(i?1)?i/n+1 化简后递推即可,输出要输出分数比较麻烦 代码: #include <cstdio> #include <cstring> #include <cmath> long long gcd(long long a, long lon

UVA 1350 - Pinary(数论+递推)

题目链接:1350 - Pinary 题意:二进制数,不能有连续的1,给定第n个数字,输出相应的二进制数 思路:先是递推,求出由n位组成的数字中有几个满足条件 dp[i] = dp[i - 1] + dp[i - 2],考虑最后一位放0和倒1位放0的情况. 然后用一个sum[i]记录满足<=i位一共的情况 接着利用二分找到给定的n > sum[i - 1],i的最大值,这个就是所求的答案的最高位. 因为如果这位放1,那么就会一共多sum[i - 1] + 1个数,那么就还需要添加n - (su

uva 1073 - Glenbow Museum(递推)

cocos2d-x升级到3.0后变化不小,除了API的变化(主要是函数和类名称变化,以及使用了C++11的不少特性,function/bind, lamda, std::thread-),创建和编译工程也做了一些简化调整.本文主要讨论一下cocos2d-x3.0 在android平台开发的环境设置及工程创建编译流程. 1.   初始设置 除了2.x所需要的python,jdk, android sdk和ndk之外,还需要部署apache-ant. 1)      在path中设置好java环境变