1. 程式人生 > WINDOWS開發 >題解 SP4354 【TWINSNOW - Snowflakes】

題解 SP4354 【TWINSNOW - Snowflakes】

首先友情提醒一下,搬題目的放漏了這題樣例其實就是

input
2
1 2 3 4 5 6
4 3 2 1 6 5
output
Twin snowflakes found.

這題我做的很窩火,終於AC了,寫篇題解新增點成就感。。。


一開始我以為是簡單題,打算先找到每朵雪花中最小的數,順時針逆時針都算一下,找字典序最小的

然後愉快WA0。因為一個雪花的手臂長度可能有相同的,比如什麼1 2 1 3 1 6這種,我的想法就炸了。


那怎麼找到一個唯一的表示方法呢?

最小表示法,不知道的可以看P1368

工藝的題解中這篇較詳細

最小表示法有了,接下來咋辦?不能用普通陣列記錄是否訪問過,因為資料範圍太大了。

有人會說hash。但是那太麻煩了其實是我不會

懶人標配:map<pos,int>mp;

(pos是存雪花六個手臂的結構體)

struct pos{
	int a[10];
}snow[N];

太棒了!我們成功了!

以下是在洛谷AC程式碼,1.42s,我最多隻能把它優化到1.05s。POJ無法AC,所以程式碼下面我會給出另一個稍有不同方法。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug printf("*");
//#define mo 1e9+7
#define inf 1e9+7
int n;
bool flag;
struct pos{
	int a[10];
	bool operator < (const pos xx) const{
		for(int i=1;i<=6;i++){
			if(xx.a[i]==a[i]) continue;
			return a[i]>xx.a[i];
		}
		return a[6]>xx.a[6];
	}
};
map<pos,int>mp;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int o[15],o2[15],it1=1,it2=2,l,ans;
		for(int j=1;j<=6;j++){
			scanf("%d",&o[j]);
			o2[7-j]=o2[7-j+6]=o[j+6]=o[j];
		}
		while(it1<=6&&it2<=6){
			l=0;
			while(l<=6&&o[it1+l]==o[it2+l]) l++;
			if(l==7){
				ans=it1;break;
			}
			if(o[it1+l]>o[it2+l]) it1=it1+l+1;
			else it2=it2+l+1;
			if(it1==it2) it2++;
		}
		ans=min(it1,it2);
		pos x,y;
		for(int j=ans;j<=ans+6-1;j++){
			x.a[j-ans+1]=o[j];
		}
		
		it1=1,it2=2;
		while(it1<=6&&it2<=6){
			l=0;
			while(l<=6&&o2[it1+l]==o2[it2+l]) l++;
			if(l==7){
				ans=it1;break;
			}
			if(o2[it1+l]>o2[it2+l]) it1=it1+l+1;
			else it2=it2+l+1;
			if(it1==it2) it2++;
		}
		ans=min(it1,it2);
		for(int j=ans;j<=ans+6-1;j++)
			y.a[j-ans+1]=o2[j];
		if(y<x){
			mp[x]++;
		}
		else mp[y]++;
		if(mp[x]>1||mp[y]>1) flag=1;
	}
	if(flag) printf("Twin snowflakes found.\n");
	else printf("No two snowflakes are alike.\n");
	return 0;
}

興高采烈地去老師的比賽提交——TLE*3

POJ機子很慢,4s時限我洛谷跑1.42s還過不去

咋辦?都怪map常數大,那就換掉。

雜湊?不太會。弄個簡單版的。

int clac(pos emm){
	int sum=0;
	for(int i=1;i<=6;i++)
		sum=(sum+emm.a[i])%mo;
	return sum;
}

雪花手臂之和%99991即可。

為什麼要取99991?因為接近n的大小。

雜湊之後可能會碰撞,所以我們要把clac值相同的給存起來,遇到有相同的就看看是不是真的相等。

別的題解用的是鏈式前向星,但是我喜歡STL,所以用了vector,會慢一些。

下面這個程式碼洛谷780msAC,POJ3829ms,vjudge上是3907ms

(我也不知道為什麼vjudge和poj差了一點

#include<iostream>
#include<vector>
#include<stdio.h>
using namespace std;
//const int N=,mo=;
//#define inf
//#define long long ll
const int mo=99991,N=100010;
int hs[mo+10],n;
struct pos{
	int a[10];
}snow[N];
vector<pos>vec[mo+10]; 
int ok(pos al,pos ar){
	for(int i=1;i<=6;i++){
		if(al.a[i]>ar.a[i]) return -1;
		if(al.a[i]<ar.a[i]) return 1;
	}
	return 0;
}
int clac(pos emm){
	int sum=0;
	for(int i=1;i<=6;i++)
		sum=(sum+emm.a[i])%mo;
	return sum;
}
int main(){
	scanf("%d",it2);
		for(int j=ans;j<=ans+6-1;j++)
			y.a[j-ans+1]=o2[j];
		pos qwq;
		if(ok(x,y)==1) qwq=x;
		else qwq=y;
		snow[i]=qwq;
		int tmp=clac(qwq);
		for(int i=0;i<vec[tmp].size();i++){
			pos v=vec[tmp][i];
			if(ok(v,qwq)==0){
				printf("Twin snowflakes found.\n");
				return 0;
			}
		}
		vec[tmp].push_back(qwq);
	}
	printf("No two snowflakes are alike.\n");
	return 0;
}