杭电 1794 方格填数

> Problem Description  
> 给你一个N*N的方格,里面都是非负整数(小于32768),
> 我们定义这个方格的总和为:其中的任何一个S*S
>1<=S<=N)的子方格中的数字的总和。由于中间有K
>0<=K<=N*N)个单位方格中的数字是0,因此现在给
> 定你M(K<=M&&M<=10000)个正整数(小于32768),
> 你可以从中选择K个,来填入原来的N*N的值为0的单位
> 方格中,从而最大化的增加我们定义的方格的总和。  
> 
> Input  
> 这里有T组测试数据,第一行输入T,T<=100> 对于测试数据,先输入一个N(N<=30),
> 然后输入一个N*N的矩阵,中间含0的元素,
> 然后给定一个M,后一行输入M个正整数。
> 
> 
> Output  
> 对于每组测试数据,输出能够最大的增加的值。  
> 
> Sample Input 
> 1
> 3
> 1 2 3
> 4 0 2
> 0 2 7
> 4
> 2 9 4 7  
> 
> Sample Output 
> 75  

先说思路:
一个变成为N的矩阵里,存在若干个0,给K个数往里填,取生成最大的情况。
那么首先K个数肯定要进行排序,择高填入。
而被填入的0,需注意不同位置的权值是不一样的,其权值体现为被正方形包含的次数。倘若能够得到每个0位置的权值,也进行排序,则可通过与填入数字从高到低一一相乘得到增加的最大值。

问题来了——如何获得各点的权值。
一个点被正方形包含的次数计算,是本题的最大难点。
可以设想,对于矩阵中坐标为(x,y)的点,包含它的正方形变成应该由1到n都有,所以何不按照包含点正方形的边长来考虑呢。
对于变成为i的正方形,可以四面八方扩散,只要求必须包含此点。
从水平方向来看,点在正方形最右和最左是两种极端情况,在不越界的情况下,横着应存在i个正方形包含此点【懒得画图,自己试试,注意是正方形不是所在矩阵】
当越界时,即x - i + 1 < 0或x + i - 1 >= n,只需减去越界部分就是允许的数量了。
竖直方向运算思路一样,二者相乘,就得到了当前i边长正方形包含这个点的个数。下面是一段专门算权值的代码,可以试试。

int main()
{
	while (1)
	{
		int x, y, n;
		int heng, shu;
		cin >> n >> x >> y;
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
			heng = i;
			if (x - i + 1 < 0)
				heng += (x - i + 1);
			if (x + i - 1 >= n)
				heng -= (x + i  - n);
			shu = i;
			if (y - i + 1 < 0)
				shu += (y - i + 1);
			if (y + i - 1 >= n)
				shu -= (y + i  - n);
			sum += (heng * shu);
			cout << i << " " << heng << " " << shu << " " << sum << endl;
		}
		cout << endl << sum<<endl;
	}
}

想明白了权值,剩下的便只需要把各部分拼接起来就可以了。
计算出0点的权值,并记录0点的个数,相乘累加就是增加的最大值。

int t, n;
bool cmp2(int x, int y)
{
	return x > y;
}
int main()
{
	int i, j, k;
	
	cin >> t;
	for (i = 0; i < t; i++)
	{
		
		int zero[901],zeron=0;
		int xx[31][31],quan[31][31];
		cin >> n;
		for (j = 0; j < n; j++)
		{
			for (k = 0; k < n; k++)
			{
				int x, y, heng, shu, sum = 0;
				cin >> xx[j][k];
				x = j;
				y = k;
				if (xx[j][k] == 0)
				{
					for (int m = 1; m <= n; m++)
					{
						heng = m;
						if (x - m + 1 < 0)
							heng += (x - m + 1);
						if (x + m - 1 >= n)
							heng -= (x + m - n);
						shu = m;
						if (y - m + 1 < 0)
							shu += (y - m + 1);
						if (y + m - 1 >= n)
							shu -= (y + m - n);
						sum += (heng * shu);
						
						//cout << i << " " << heng << " " << shu << " " << sum << endl;
					}
					zero[zeron++] = sum;
				}

			}

		}
		sort(zero, zero + zeron,cmp2);
		int bu;
		int kexuan[100001];
		cin >> bu;
		for (j = 0; j < bu; j++)
		{
			cin >> kexuan[j];
		}
		sort(kexuan, kexuan + bu, cmp2);
		long long int all=0;
		for (j = 0; j < zeron; j++)
		{
			all += zero[j] * kexuan[j];
		}
		cout << all << endl;
	}

}


你可能感兴趣的:(杭电oj,c++,算法,数据结构)