抽象后的题意:给一个不超过30个点的图,A从中选不超过5个点涂红绿两种颜色,B用黑白两种颜色把剩下的涂完,任意一条边两端的颜色不同,求每种颜色至少用涂一次的方案数
思路:枚举A涂的点的集合,将原图分成两个子图P和Q,P和Q互相不影响,因为涂的颜色不同。考虑A在P中涂颜色,由于一条边的两端的颜色不能相同,于是对P进行二分染色,如果是非二分图,那么方案数为0,否则令P的连通分量个数为cnt,如果点集小于2则方案总数为0,否则如果边数为0,说明给P涂1种颜色的答案为2,最后答案为2cnt-2,边数不为0则答案为2cnt。Q与P同理。
#pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define fillarray(a, b) memcpy(a, b, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; #ifndef ONLINE_JUDGE void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} #endif template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const double EPS = 1e-12; /* -------------------------------------------------------------------------------- */ const int maxn = 500; int n, m; struct Ufs { int fa[maxn]; void init() { for (int i = 0; i < maxn; i ++) fa[i] = i; } int getfa(int u) { return u == fa[u]? u : fa[u] = getfa(fa[u]); } int add(int u, int v) { fa[getfa(u)] = getfa(v); } }; Ufs ufs; inline int makeid(int x, int y) { return x * m + y; } bool e[30][30]; int newnode[maxn]; int c; ll ans = 0; bool E[30][30]; int vis[30]; bool dfs(int u, int c, int color) { vis[u] = color; for (int i = 0; i < c; i ++) { if (E[u][i]) { if (!vis[i]) if (!dfs(i, c, 3 - color)) return false; if (vis[i] == vis[u]) return false; } } return true; } int count(bool sube[30][30], int c) { int ans = 0; fillchar(vis, 0); for (int i = 0; i < c; i ++) { for (int j = 0; j < c; j ++) { E[i][j] = sube[i][j]; } } for (int i = 0; i < c; i ++) { if (!vis[i]) { ans ++; if (!dfs(i, c, 1)) return - INF; } } return ans; } int useonecolor(bool sube[30][30], int c) { for (int i = 0; i < c; i ++) { for (int j = 0; j < c; j ++) { if (sube[i][j]) return 0; } } if (c) return 2; return 1; } int s[6], top = 0; void dfs(int p, int r) { if (r == 0) { int rst[5], extra[30]; int t = 0; bool vis[30] = {}, sube[30][30] = {}, sube2[30][30] = {}; for (int i = 0; i < top; i ++) { rst[i] = s[i]; vis[s[i]] = true; } for (int i = 0; i < c; i ++) { if (!vis[i]) extra[t ++] = i; } for (int j = 0; j < top; j ++) { for (int k = 0; k < top; k ++) { sube[j][k] = e[rst[j]][rst[k]]; } } for (int j = 0; j < c - top; j ++) { for (int k = 0; k < c - top; k ++) { sube2[j][k] = e[extra[j]][extra[k]]; } } ll girl = count(sube, top), boy = count(sube2, c - top); if (girl < 0 || boy < 0) return ; girl = 1 << girl; boy = 1 << boy; ans += (girl - useonecolor(sube, top)) * (boy - useonecolor(sube2, c - top)); return ; } for (int i = p; i <= c - r; i ++) { s[top ++] = i; dfs(i + 1, r - 1); top --; } } char str[30][30]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int cas = 0; while (cin >> n >> m) { ufs.init(); for (int i = 0; i < n; i ++) { scanf("%s", str[i]); for (int j = 0; str[i][j]; j ++) { if (j && str[i][j] == str[i][j - 1]) ufs.add(makeid(i, j), makeid(i, j - 1)); if (i && str[i][j] == str[i - 1][j]) ufs.add(makeid(i, j), makeid(i - 1, j)); } } c = 0; for (int i = 0; i < n; i ++) { for (int j = 0; j < m; j ++) { if (ufs.getfa(makeid(i, j)) == makeid(i, j)) newnode[makeid(i, j)] = c ++; } } fillchar(e, 0); for (int i = 0; i < n; i ++) { for (int j = 0; j < m; j ++) { if (i && str[i][j] != str[i - 1][j]) e[newnode[ufs.getfa(makeid(i, j))]][newnode[ufs.getfa(makeid(i - 1, j))]] = true; if (j && str[i][j] != str[i][j - 1]) e[newnode[ufs.getfa(makeid(i, j))]][newnode[ufs.getfa(makeid(i, j - 1))]] = true; } } for (int i = 0; i < c; i ++) { for (int j = 0; j < c; j ++) { e[i][j] = e[i][j] || e[j][i]; } //print(e[i], e[i] + c); } ans = 0; for (int i = 0; i <= min(5, c); i ++) dfs(0, i); printf("Case %d: ", ++ cas); cout << ans << endl; } return 0; }