15年國賽 模型染色

標題:模型染色

在電影《超能陸戰隊》中,小宏可以使用他的微型機器人組合成各種各樣的形狀。
現在他用他的微型機器人拼成了一個大玩具給小朋友們玩。爲了更加美觀,他決定給玩具染色。

小宏的玩具由n個球型的端點和m段連接這些端點之間的邊組成。下圖給出了一個由5個球型端點和4條邊組成的玩具,看上去很像一個分子的球棍模型。
 
由於小宏的微型機器人很靈活,這些球型端點可以在空間中任意移動,同時連接相鄰兩個球型端點的邊可以任意的伸縮,這樣一個玩具可以變換出不同的形狀。在變換的過程中,邊不會增加,也不會減少。
小宏想給他的玩具染上不超過k種顏色,這樣玩具看上去會不一樣。如果通過變換可以使得玩具變成完全相同的顏色模式,則認爲是本質相同的染色。現在小宏想知道,可能有多少種本質不同的染色。

【輸入格式】
輸入的第一行包含三個整數n, m, k,
分別表示小宏的玩具上的端點數、邊數和小宏可能使用的顏色數。端點從1到n編號。
接下來m行每行兩個整數a, b,表示第a個端點和第b個端點之間有一條邊。輸入保證不會出現兩條相同的邊。

【輸出格式】
輸出一行,表示本質不同的染色的方案數。由於方案數可能很多,請輸入方案數除10007的餘數。

【樣例輸入】
3 2 2
1 2
3 2
【樣例輸出】
6
【樣例說明】
令(a, b, c)表示第一個端點染成a,第二個端點染成b,第三個端點染成c,則下面6種本質不同的染色:(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 2), (2, 2, 2)。
而(2, 1, 1)與(1, 1, 2)是本質相同的,(2, 2, 1)與(1, 2, 2)是本質相同的。

【數據規模與約定】
對於20%的評測數據,1<=n<=5, 1<=k<=2。
對於50%的評測數據,1<=n<=10, 1<=k<=8。
對於100%的評測數據,1<=n<=10, 1<=m<=45, 1<=k<=30。

資源約定:
峯值內存消耗 < 512M
CPU消耗  < 5000ms

是一個比較複雜的計數問題,需要使用多種顏色對圖進行染色。
如果使用搜索方法,可以獲得本題比較基礎的分,搜索比較複雜,需要判斷圖的同構。
一種正確的做法是使用組合數學的Polya定理。這個定理需要對於給定的圖求出對於這個圖的所有置換。
可以使用枚舉所有可能的排列,判斷這個排列是否與原圖同構來判斷是否是一個置換。
求完置換後求出每個置換循環節數量,利用Polya定理可以求解。
需要用到比較複雜的知識,同構的判斷容易出錯。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN = 100;
const int MOD = 10007;
int n, m, k;
int g[MAXN][MAXN];
int mp[MAXN], q[MAXN];
long long tt[MAXN];
long long pw[MAXN];

bool isIsomorphism(int p)
{
	for (int i = 1; i < p; ++i)
		if (g[p][i] ^ g[q[p]][q[i]])
			return false;
	return true;
}

void isomorphismSearch(int p, int cnt)
{
	if (p > n)
	{
		tt[cnt]++;
		return ;
	}
	for (int i = p; i <= n; ++i)
	{
		swap(q[p], q[i]);
		if (isIsomorphism(p))
		{
			int r = q[p];
			while (r<p)
				r = q[r];
			isomorphismSearch(p+1, cnt+(r==p));
		}
		swap(q[p], q[i]);
	}
}

void solve(long long a, long long b, long long c, long long &x, long long &y)
{
	if (b==0)
	{
		x = c/a; y = 0;
		return ;
	}
	solve(b, a%b, c, y, x);
	y -= a/b * x;
}

int main()
{
	cin >> n >> m >> k;
	for (int i = 0; i < m; ++i)
	{
		int a, b;
		cin >> a >> b;
		g[a][b] = g[b][a] = 1;
	}
	for (int i = 1; i <= n; ++i)
		q[i] = i;
	pw[0] = 1;
	for (int i = 1; i <= n; ++i)
		pw[i] = (pw[i-1]*k) % MOD;

	memset(tt, 0, sizeof(tt));
	isomorphismSearch(1, 0);
	long long ans = 0, stt = 0;
	for (int i = 1; i <= n; ++i)
	{
		ans += ((tt[i]%MOD)*pw[i])%MOD;
		stt += tt[i];
	}
	ans %= MOD;
	long long x, y;
	solve(stt%MOD, MOD, ans, x, y);
	x %= MOD;
	if (x < 0)
		x += MOD;
	cout << x << endl;
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章