poj 1021 2D_NIM

这道题有两个难点。

第一个难点就是读懂题意,众所周知,poj一般都是,读题两小时,解题五分钟。

题目的意思是一群点上下左右链接就算一个点群,一个点群旋转后依然等于原点群。给你两个图,里面有很多个点群,两个图对应点群一样就算两个图一样,问你这两个图一不一样。

第二个难点就是图的同构问题(“图”指上文中的点群),主要是算图的hash值,hash值一样的就算同一个图,hash值有很多种算法,一种是算每个点到其他点的距离之和,算出来的hash是一个值,不过代码不好实现,另一种是算每个点上下左右能走的距离,算出来的hash值是一个数组(包含n个点),我用的就是第二种算法。

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) x<<1
#define r(x) x<<1|1
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

int mmap[200][200];
int t, w, h, n;
int pos[111111][2];
int mhash[2][5555];
int x, y;

int main() {
	cin >> t;
	while (t--) {
		ms(mhash, 0);
		cin >> w >> h >> n;
		ms(mmap, 0);
		for (int i = 0; i < n; i++) {
			cin >> pos[i][0] >> pos[i][1];
			mmap[pos[i][0]][pos[i][1]] = 1;
		}

		for (int i = 0; i < n; i++) {
			x = pos[i][0];
			y = pos[i][1];

			for (int j = x; j < w && mmap[j][y] == 1; j++)
				mhash[0][i]++;
			for (int j = x; j >= 0 && mmap[j][y] == 1; j--)
				mhash[0][i]++;
			for (int j = y; j < h && mmap[x][j] == 1; j++)
				mhash[0][i]++;
			for (int j = y; j >= 0 && mmap[x][j] == 1; j--)
				mhash[0][i]++;
		}

		sort(mhash[0], mhash[0] + n);

		ms(mmap, 0);
		for (int i = 0; i < n; i++) {
			cin >> pos[i][0] >> pos[i][1];
			mmap[pos[i][0]][pos[i][1]] = 1;
		}

		for (int i = 0; i < n; i++) {
			x = pos[i][0];
			y = pos[i][1];

			for (int j = x; j < w && mmap[j][y] == 1; j++)
				mhash[1][i]++;
			for (int j = x; j >= 0 && mmap[j][y] == 1; j--)
				mhash[1][i]++;
			for (int j = y; j < h && mmap[x][j] == 1; j++)
				mhash[1][i]++;
			for (int j = y; j >= 0 && mmap[x][j] == 1; j--)
				mhash[1][i]++;
		}

		sort(mhash[1], mhash[1] + n);

		bool flag = true;
		for (int i = 0; i < n; i++) {
			if (mhash[0][i] != mhash[1][i]) {
				flag = false;
				break;
			}
		}

		if (flag)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}

	return 0;
}

不过对于第二种算法,直接用一个int保存所以hash值的和一样能够通过,不知道怎么证明,但我也找不出反例

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) x<<1
#define r(x) x<<1|1
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

int mmap[200][200];
int t, w, h, n;
int pos[111111][2];
int mhash[2];
int x, y;

int main() {
	cin >> t;
	while (t--) {
		ms(mhash, 0);
		cin >> w >> h >> n;
		ms(mmap, 0);
		for (int i = 0; i < n; i++) {
			cin >> pos[i][0] >> pos[i][1];
			mmap[pos[i][0]][pos[i][1]] = 1;
		}

		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				cout << mmap[i][j] << " ";
			}
			cout << endl;
		}

		for (int i = 0; i < n; i++) {
			x = pos[i][0];
			y = pos[i][1];

			for (int j = x; j < w && mmap[j][y] == 1; j++)
				mhash[0]++;
			for (int j = x; j >= 0 && mmap[j][y] == 1; j--)
				mhash[0]++;
			for (int j = y; j < h && mmap[x][j] == 1; j++)
				mhash[0]++;
			for (int j = y; j >= 0 && mmap[x][j] == 1; j--)
				mhash[0]++;
		}

		ms(mmap, 0);
		for (int i = 0; i < n; i++) {
			cin >> pos[i][0] >> pos[i][1];
			mmap[pos[i][0]][pos[i][1]] = 1;
		}
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				cout << mmap[i][j] << " ";
			}
			cout << endl;
		}

		for (int i = 0; i < n; i++) {
			x = pos[i][0];
			y = pos[i][1];

			for (int j = x; j < w && mmap[j][y] == 1; j++)
				mhash[1]++;
			for (int j = x; j >= 0 && mmap[j][y] == 1; j--)
				mhash[1]++;
			for (int j = y; j < h && mmap[x][j] == 1; j++)
				mhash[1]++;
			for (int j = y; j >= 0 && mmap[x][j] == 1; j--)
				mhash[1]++;
		}

		if (mhash[0] == mhash[1])
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值