IOPC12-IOPC1213 : Colouring graphs
問題概要
ノード数N(<100)のグラフがある。Q(<1000)個のクエリがあって、
- 辺を追加する
- 辺を削除する
- K(>1)彩色の仕方が何通りあるか出力する
を処理する。ただしグラフは常に森である。
解法
答えは、各連結成分に対してK*(K-1)^(size-1)をかけ合わせる。
連結成分の個数とサイズを求めるのは、制約が緩いので愚直に処理して間に合う。
実はサイズを求める必要はない(K^C * (K-1)^(N-C) が答。Cは連結成分の個数)。
acceptされたコード
計算量O(N+Q^2)。
#include <cstdio> #include <vector> #include <cstring> using namespace std; typedef long long int64; const int MAX_N = 100; const int64 MOD = 100000007; int N, M, Q; vector<int> graph[MAX_N]; bool visited[MAX_N]; int64 pow_binary(int64 x, int n){ int64 ret = 1; for(;n;n>>=1){ if( n&1 ){ ret = ret * x % MOD; } x = x * x % MOD; } return ret; } void init(){ scanf("%d%d%d", &N, &M, &Q); for(int i=0; i<N; i++){ graph[i].clear(); } for(int i=0; i<M; i++){ int x, y; scanf("%d%d", &x, &y); graph[x].push_back(y); graph[y].push_back(x); } } void add(){ int x, y; scanf("%d%d", &x, &y); graph[x].push_back(y); graph[y].push_back(x); } void del(){ int x, y; scanf("%d%d", &x, &y); for(int k=0; k<2; k++){ vector<int> tmp; for(int i=0; i<(int)graph[x].size(); i++){ if(graph[x][i] != y){ tmp.push_back(graph[x][i]); } } graph[x] = tmp; swap(x, y); } } int dfs(int v){ visited[v] = true; int ret = 1; for(int i=0; i<(int)graph[v].size(); i++){ const int u = graph[v][i]; if(!visited[u]){ ret += dfs(u); } } return ret; } int count(int k){ memset(visited, false, sizeof(visited)); int64 ans = 1; for(int i=0; i<N; i++)if(!visited[i]){ int sz = dfs(i); ans = ans * k % MOD; ans = ans * pow_binary(k-1, sz-1) % MOD; } return (int)ans; } void query(){ int k; scanf("%d", &k); if(k==0){ add(); } else if(k==1){ del(); } else{ printf("%d\n", count(k)); } } int main(){ int T; scanf("%d", &T); for(;T--;){ init(); for(int i=0; i<Q; i++){ query(); } } return 0; }