標題:模型染色
在電影《超能陸戰隊》中,小宏可以使用他的微型機器人組合成各種各樣的形狀。
現在他用他的微型機器人拼成了一個大玩具給小朋友們玩。爲了更加美觀,他決定給玩具染色。
小宏的玩具由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;
}