VK Cup 2018 Round 2: A. Mystical Mosaic(思维)

time limit per test  1 second
memory limit per test  256 megabytes
input  standard input
output  standard output

There is a rectangular grid of n rows of m initially-white cells each.

Arkady performed a certain number (possibly zero) of operations on it. In the i-th operation, a non-empty subset of rows Ri and a non-empty subset of columns Ci are chosen. For each row r in Ri and each column c in Ci, the intersection of row r and column c is coloured black.

There's another constraint: a row or a column can only be chosen at most once among all operations. In other words, it means that no pair of (i, j) (i < j) exists such that  or , where  denotes intersection of sets, and  denotes the empty set.

You are to determine whether a valid sequence of operations exists that produces a given final grid.

Input

The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 50) — the number of rows and columns of the grid, respectively.

Each of the following n lines contains a string of m characters, each being either '.' (denoting a white cell) or '#' (denoting a black cell), representing the desired setup.

Output

If the given grid can be achieved by any valid sequence of operations, output "Yes"; otherwise output "No" (both without quotes).

You can print each character in any case (upper or lower).

Examples
input
5 8
.#.#..#.
.....#..
.#.#..#.
#.#....#
.....#..
output
Yes
input
5 5
..#..
..#..
#####
..#..
..#..
output
No
input
5 9
........#
#........
..##.#...
.......#.
....#.#.#
output
No


题意:一个n*m的矩阵,一开始所有格子都是空的,你每次可以选择若干列和若干行,并在这些行和列的交点上放上一枚棋子,每一行/列至多被选一次,先给你一种最终情况,问你能否实现


仔细分析一下就会发现,如果有三个棋子在某个矩形的三个顶点上,那么这个矩形的第四个顶点上一定要有棋子(三个棋子作为定点可以构成一个直角三角形,其中直角边平行于x轴和y轴,那么这三个棋子就一定在某个矩形的三个顶点上)

所以只要暴力枚举任意一对棋子作为矩形的其中一条斜对角线,然后判断下另一条对角线上棋子情况就OK了

复杂度O(n²m²)


#include<stdio.h>
char str[55][55];
int main(void)
{
	int n, m, i, j, x, y;
	scanf("%d%d", &n, &m);
	for(i=1;i<=n;i++)
		scanf("%s", str[i]+1);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(str[i][j]=='.')
				continue;
			for(x=1;x<=n;x++)
			{
				for(y=1;y<=n;y++)
				{
					if(str[x][y]=='.' || i==x || j==y)
						continue;
					if(str[i][y]=='#' && str[x][j]=='.' || str[i][y]=='.' && str[x][j]=='#')
					{
						printf("No\n");
						return 0;
					}
				}
			}
		}
	}
	printf("Yes\n");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了解决这个问题,我们可以先对两个数组进行排序,然后用双指针法来找到所有相似的子数组。具体实现如下: ```c #include <stdio.h> #include <stdlib.h> #define MAX_N 1000000 int M[MAX_N], N[MAX_N]; int m, n; int compare(const void *a, const void *b) { return *(int*)a - *(int*)b; } int count_similar() { int i = 0, j = 0; int count = 0; while (i < m && j < n) { if (M[i] == N[j]) { // 找到相同的元素 int k = j; while (k < n && N[k] == N[j]) { k++; } count += k - j; // 加上与N[j]相同的元素的个数 i++; j = k; } else if (M[i] < N[j]) { // M[i]较小,需要增加N中的元素 i++; } else { // M[i]较大,需要减少N中的元素 j++; } } return count; } int main() { scanf("%d%d", &m, &n); for (int i = 0; i < m; i++) { scanf("%d", &M[i]); } for (int i = 0; i < n; i++) { scanf("%d", &N[i]); } qsort(M, m, sizeof(int), compare); qsort(N, n, sizeof(int), compare); printf("%d\n", count_similar()); return 0; } ``` 首先读入两个数组的长度和元素,然后对它们进行排序。然后用双指针法找到所有相似的子数组,具体方法如下: 1. 初始化两个指针i和j,分别指向M和N的开头; 2. 如果M[i]等于N[j],说明找到了一个相似的子数组,接着向右移动j,直到N[j]不等于N[j+1]; 3. 如果M[i]小于N[j],说明N[j]需要增加,所以向右移动i; 4. 如果M[i]大于N[j],说明N[j]需要减少,所以向右移动j; 5. 重复2~4步,直到i到达M的末尾或j到达N的末尾。 遍历过程中,我们用一个计数器count来累计相似的子数组的个数,每当找到一个相似的子数组时,我们就把与N[j]相同的元素的个数加到count中。最后返回count即可。 时间复杂度为O(MlogM + NlogN),空间复杂度为O(M + N)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值