[csu1508 地图的四着色]二分图染色

抽象后的题意:给一个不超过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;
}
posted @ 2015-08-23 04:32  jklongint  阅读(471)  评论(0编辑  收藏  举报