UVA - 1156 Pixel Shuffle (置换+模拟)

Description

Shuffling the pixels in a bitmap image sometimes yields random looking images. However, by repeating the shuffling enough times, one finally recovers the original images. This should be no surprise, since ``shuffling" means applying a one-to-one mapping
(or permutation) over the cells of the image, which come in finite number.

Problem

Your program should read a number n , and a series of elementary transformations that define a ``shuffling"
of
nxn images. Then, your program should compute the minimal number
m(m > 0) , such that
m applications of always yield the original
nxn image.

For instance if is counter-clockwise 90
o rotation then m = 4 .

Input

The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.

Input is made of two lines, the first line is number n (
2n210
, n even). The number n is the size of images, one image is represented internally by a
nxn pixel matrix
(aji) , where i is the row number and
j is the column number. The pixel at the upper left corner is at row 0 and column 0.

The second line is a non-empty list of at most 32 words, separated by spaces. Valid words are the keywords
id, rot,
sym, bhsym, bvsym,
div and mix, or a keyword followed by ``-". Each keyword key designates an elementary transform (as defined by Figure 1), and
key- designates the inverse of transform
key. For instance, rot- is the inverse of counter-clockwise 90o rotation, that is clockwise 90
o rotation. Finally, the list
k1, k2,..., kp designates the compound transform
=
k1ok2o ... okp . For instance, ``
bvsym rot-" is the transform that first performs clockwise 90
o rotation and then vertical symmetry on the lower half of the image.

Figure 1: Transformations of image (aji) into image
(bji)

Output

For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line.

Your program should output a single line whose contents is the minimal number
m(m > 0) such that
is the identity. You may assume that, for all test input, you have
m < 231 .

Sample Input

2

256
rot- div rot div

256
bvsym div mix

Sample Output

8

63457
题意:给你n*n的矩阵和几种操作,问重复几次后会得到原图
思路:每个命令都是一个置换,操作序列就是置换的乘积,我们可以最终的处理出这个矩阵,一个结论:对于一个长度为l的循环A,当且仅当m是l的整数倍的时候A^m才是全等置换,所以答案是多个循环的最小
公倍数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1100;

int n, g[maxn][maxn], vis[maxn][maxn], save[maxn][maxn];
char str[maxn], tmp[maxn];

int gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a % b);
}

int lcm(int a, int b) {
	return a / gcd(a, b) * b;
}

void id() {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			g[i][j] = save[i][j];
}

void rot(int flag) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (flag)
				save[i][j] = g[n-j-1][i];
			else save[n-j-1][i] = g[i][j];
		}
	id();
}

void sym(int flag) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			save[i][j] = g[i][n-1-j];
	id();
}

void bhsym(int flag) {
	for (int i = 0; i < n/2; i++)
		for (int j = 0; j < n; j++)
			save[i][j] = g[i][j];
	for (int i = n/2; i < n; i++)
		for (int j = 0; j < n; j++)
			save[i][j] = g[i][n-1-j];
	id();
}

void bvsym(int flag) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (i < n / 2)
				save[i][j] = g[i][j];
			else save[i][j] = g[3 * n / 2 - 1 - i][j];
		}
	id();
}

void div(int flag) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if (flag == 1) {
				if (i & 1)
					save[i / 2 + n / 2][j] = g[i][j];
				else save[i / 2][j] = g[i][j];
			}
			else {
				if (i & 1)
					save[i][j] = g[i / 2 + n / 2][j];
				else save[i][j] = g[i / 2][j];
			}
		}
	id();
}

void mix(int flag) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			if ((i & 1) == 0) {
				if (flag) {
					if ((j & 1) == 0)
						save[i][j] = g[i][j / 2];
					else save[i][j] = g[i + 1][j / 2];
				}
				else {
					if ((j & 1) == 0)
						save[i][j / 2] = g[i][j];
					else save[i + 1][j / 2] = g[i][j];
				}
			}
			else {
				if (flag) {
					if ((j & 1) == 0)
						save[i][j] = g[i - 1][n / 2 + j / 2];
					else save[i][j] = g[i][n / 2 + j / 2];
				}
				else {
					if ((j & 1) == 0)
						save[i - 1][n / 2 + j / 2] = g[i][j];
					else save[i][n / 2 + j / 2] = g[i][j];

				}
			}
		}
	id();
}

void change(char *str) {
	int len = strlen(str);
	int flag = 1;
	if (str[0] == '-') {
		flag = 0;
		str++;
	}
	if (strcmp(str, "tor") == 0) rot(flag);
	else if (strcmp(str, "mys") == 0) sym(flag);
	else if (strcmp(str, "myshb") == 0) bhsym(flag);
	else if (strcmp(str, "mysvb") == 0) bvsym(flag);
	else if (strcmp(str, "vid") == 0) div(flag);
	else if (strcmp(str, "xim") == 0) mix(flag);
}

void tra() {
	int len = strlen(str);
	int sn = 0;
	for (int i = len - 1; i >= 0; i--) {
		if (str[i] == ' ') {
			tmp[sn] = '\0';
			change(tmp);
			sn = 0;
		}
		else {
			tmp[sn++] = str[i];
		}
	}
	tmp[sn] = '\0';
	change(tmp);
}

int solve() {
	int ans = 1;
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (!vis[i][j]) {
				vis[i][j] = 1;
				int cnt = 1;
				int x = g[i][j] / n;
				int y = g[i][j] % n;
				while (!vis[x][y]) {
					cnt++;
					vis[x][y] = 1;
					int t = g[x][y] / n;
					y = g[x][y] % n;
					x = t;
				}
				ans = lcm(ans, cnt);
			}
		}
	}
	return ans;
}

void init() {
	scanf("%d", &n);
	getchar();
	gets(str);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			g[i][j] = i * n + j;
		}
	}
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		init();
		tra();
		printf("%d\n", solve());
		if (t)
			printf("\n");
	}
	return 0;
}

时间: 2024-10-11 00:00:56

UVA - 1156 Pixel Shuffle (置换+模拟)的相关文章

uva 1156 - Pixel Shuffle(模拟+置换)

题目链接:uva 1156 - Pixel Shuffle 题目大意:给定一个N*N的黑白位图,有7种操作,并且对应在指令后加上'-'即为操作的逆,给定N和一系列操作,(从最后一个开始执行),问说这一套指令需要执行多少次才能形成循环. 解题思路:模拟指令执行后获得一个置换,分解成若干的循环,各个循环长度的最小公倍数即使答案. #include <cstdio> #include <cstring> #include <algorithm> using namespace

uva 10710 - Chinese Shuffle(完美洗牌)

题目链接:uva 10710 - Chinese Shuffle 题目大意:给出n张牌,按照顺序排列好,进行n-1次完美洗牌,问是否可以变成原来德序列. 解题思路:根据完美洗牌的性质,于是第x张牌经过p次后德位置有x?2p,于是只需要证明第1张牌最后是否在远处即可. #include <cstdio> #include <cstring> typedef long long ll; ll pow_mod(ll a, ll n, ll mod) { ll ans = 1; while

UVA 1016 - Silly Sort(置换分解+贪心)

UVA 1016 - Silly Sort 题目链接 题意:给定一个序列,数字都不同,每次可以交换两个数字,交换的代价为两数之和,要求出把这个序列变成递增最小代价 思路:利用置换的分解原理,可以把序列的每条循环单独考虑,对于每条循环而言,不断交换肯定每个数字至少会换到一次,再利用贪心的思想,如果每次拿循环中的最小值去置换,那么就是这个最小值会用长度-1次,而剩下的数字各一次,注意这里还有一种可能优的方法,就是先把整个序列中的最小值换到该循环中,等置换完再换出去,两种都考虑进来即可 代码: #in

uva 1016 - Silly Sort(置换+贪心)

题目链接:uva 1016 - Silly Sort 题目大意:给定一个长度为n的序列,每次操作可以交换任意两个数的位置,代价为两个数的和,求最小代价,将序列排成有序的. 解题思路:给定序列根据数的大小映射成一个置换,分解置换的循环,对于每个循环中,肯定是用值最小的逐个去交换的代价最小,但是要考虑,可以将最小的值与序列中最小值交换,用它代替去交换,最后再换回来.取两种情况中最优的. #include <cstdio> #include <cstring> #include <

UVA 10142 Australian Voting(模拟)

题意:澳大利亚投票系统要求选民们将所有候选人按愿意选择的程度排序,一张选票就是一个排序.一开始,每张选票的首选项将被统计.若有候选人得票超过50%,他讲直接胜出:否则,所有并列最低的候选人出局,而那些将出局候选人排在第一位的选票将被重新统计为排名最高的未出局候选人.这一筛选过程将持续进行,直到某个候选人得到超过50%的选票,或所有候选人得票相同. #include<cstdio> #include<cstring> #include<iostream> #include

LA 3510 (置换 循环分解) Pixel Shuffle

思路挺简单的,题目中的每个命令(包括命令的逆)相当于一个置换. 用O(n2k)的时间复杂度从右往左求出这些置换的乘积A,然后求m使Am = I(I为全等置换) 还是先把A分解循环,m则等于所有循环节长度的最小公倍数. 需要注意的是: 执行命令是从右往左执行的,这是题目中说的=_= 其他命令还好,mix那个命令把我搞得晕头转向,题中给的是反的,我们要反过来求原图像(i, j)在新图像中的位置. 1 #include <cstdio> 2 #include <cstring> 3 #i

UVA - 10023 - Square root (模拟手算开方)

题目传送:UVA - 10023 思路:模拟手算开方,不想用c/c++,感觉太麻烦了,就直接用的java里的BigInteger类来写的,写了好久......Java还是得看看书呀,手算开方参考的这里 AC代码: import java.util.Scanner; import java.math.BigInteger; public class Main { static void fun(BigInteger x) { String str; str = x.toString(); str

UVA - 133 The Dole Queue(模拟链表)

点击打开链接 n的人围成一个环,然后按逆时针编号1-n,一个人从1开始逆时针数k个数,另一个人从N开始顺时针数m个数,然后 数出来的两个人出列(两个人可能一样)出列,然后继续此过程,直到全部人都出列为止. 思路是用循环链表来模拟,注意 要分情况来讨论. #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #inclu

UVA 1594:Ducci Sequence (模拟 Grade E)

题意: 对于一个n元组(a0,a1,...),一次变换后变成(|a0-a1|,|a1-a2|,...) 问1000次变换以内是否存在循环. 思路: 模拟,map判重 代码: #include <cstdio> #include <cstring> #include <map> #include <cmath> #include <algorithm> using namespace std; struct Node{ int a[16]; int