抽象后的题意:给一个不超过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=;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?:-;
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?:-;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 = ; int n, m; struct Ufs {
int fa[maxn];
void init() { for (int i = ; 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[][];
int newnode[maxn];
int c; ll ans = ; bool E[][];
int vis[]; bool dfs(int u, int c, int color) {
vis[u] = color;
for (int i = ; i < c; i ++) {
if (E[u][i]) {
if (!vis[i]) if (!dfs(i, c, - color)) return false;
if (vis[i] == vis[u]) return false;
}
}
return true;
} int count(bool sube[][], int c) {
int ans = ;
fillchar(vis, );
for (int i = ; i < c; i ++) {
for (int j = ; j < c; j ++) {
E[i][j] = sube[i][j];
}
}
for (int i = ; i < c; i ++) {
if (!vis[i]) {
ans ++;
if (!dfs(i, c, )) return - INF;
}
}
return ans;
} int useonecolor(bool sube[][], int c) {
for (int i = ; i < c; i ++) {
for (int j = ; j < c; j ++) {
if (sube[i][j]) return ;
}
}
if (c) return ;
return ;
} int s[], top = ; void dfs(int p, int r) {
if (r == ) {
int rst[], extra[];
int t = ;
bool vis[] = {}, sube[][] = {}, sube2[][] = {};
for (int i = ; i < top; i ++) {
rst[i] = s[i];
vis[s[i]] = true;
}
for (int i = ; i < c; i ++) {
if (!vis[i]) extra[t ++] = i;
}
for (int j = ; j < top; j ++) {
for (int k = ; k < top; k ++) {
sube[j][k] = e[rst[j]][rst[k]];
}
}
for (int j = ; j < c - top; j ++) {
for (int k = ; k < c - top; k ++) {
sube2[j][k] = e[extra[j]][extra[k]];
}
}
ll girl = count(sube, top), boy = count(sube2, c - top);
if (girl < || boy < ) return ;
girl = << girl;
boy = << 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 + , r - );
top --;
}
} char str[][]; int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int cas = ;
while (cin >> n >> m) {
ufs.init();
for (int i = ; i < n; i ++) {
scanf("%s", str[i]);
for (int j = ; str[i][j]; j ++) {
if (j && str[i][j] == str[i][j - ]) ufs.add(makeid(i, j), makeid(i, j - ));
if (i && str[i][j] == str[i - ][j]) ufs.add(makeid(i, j), makeid(i - , j));
}
}
c = ;
for (int i = ; i < n; i ++) {
for (int j = ; j < m; j ++) {
if (ufs.getfa(makeid(i, j)) == makeid(i, j)) newnode[makeid(i, j)] = c ++;
}
}
fillchar(e, );
for (int i = ; i < n; i ++) {
for (int j = ; j < m; j ++) {
if (i && str[i][j] != str[i - ][j]) e[newnode[ufs.getfa(makeid(i, j))]][newnode[ufs.getfa(makeid(i - , j))]] = true;
if (j && str[i][j] != str[i][j - ]) e[newnode[ufs.getfa(makeid(i, j))]][newnode[ufs.getfa(makeid(i, j - ))]] = true;
}
}
for (int i = ; i < c; i ++) {
for (int j = ; j < c; j ++) {
e[i][j] = e[i][j] || e[j][i];
}
//print(e[i], e[i] + c);
}
ans = ;
for (int i = ; i <= min(, c); i ++) dfs(, i);
printf("Case %d: ", ++ cas);
cout << ans << endl;
}
return ;
}

[csu1508 地图的四着色]二分图染色的更多相关文章

  1. CSU 1508:地图的四着色(DFS+剪枝)

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1508 题意:地图中四联通的块是一个国家,A和B每个人可以涂两种颜色,且B不能涂超过5次,相邻的国家 ...

  2. UVA-10004-Bicoloring二分图染色

    题意:给一张图,判断是不是二分图: 自己一开始不知道是二分图染色,理解的是任意三点不能互相连接 可能以后遇到这样的模型,可以往二分图想: 首先怎么判定一个图是否为二分图 从其中一个定点开始,将跟它邻接 ...

  3. NOIP2008双栈排序[二分图染色|栈|DP]

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  4. 洛谷P1330封锁阳光大学[二分图染色]

    题目描述 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街.河蟹看到欢快的曹,感到不爽.河蟹决定封锁阳光大学,不让曹刷街. 阳光大学的校园是一张由N个点构成的无向图,N个点之间由M ...

  5. POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]

    Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 12439   Acce ...

  6. 【POJ 2942】Knights of the Round Table(点双连通分量,二分图染色)

    圆桌会议必须满足:奇数个人参与,相邻的不能是敌人(敌人关系是无向边). 求无论如何都不能参加会议的骑士个数.只需求哪些骑士是可以参加的. 我们求原图的补图:只要不是敌人的两个人就连边. 在补图的一个奇 ...

  7. Codeforces Round #311 (Div. 2) D - Vitaly and Cycle(二分图染色应用)

    http://www.cnblogs.com/wenruo/p/4959509.html 给一个图(不一定是连通图,无重边和自环),求练成一个长度为奇数的环最小需要加几条边,和加最少边的方案数. 很容 ...

  8. SGU 172.eXam(二分图染色)

    时间限制:0.25s 空间限制:4M 题意: 将n(n<200)个点分成两个集合,给出m(m<=30000)对不能在一个集合的点对,判断能否分成满足要求的集合,输出其中一个集合和集合的总数 ...

  9. noip 2010 关押罪犯 (二分图染色 并茶几)

    /* 二分图染色版本 两个监狱对应二部图的两部分 在给定的怨气值里二分 对于每一个Ci 进行染色判断是否合法 染色的时候 如果这条边的ci > Ci 这两个人就带分开 即染成不同的颜色 如果染色 ...

随机推荐

  1. Java数组模拟环形队列

    2.环形队列 (上一篇队列:https://www.cnblogs.com/yxm2020/p/12676323.html) 百度百科 1.假溢出 ​ 系统作为队列用的存储区还没有满,但队列却发生了溢 ...

  2. WinRAR代码执行漏洞复现

    漏洞介绍 WinRAR 是一款流行的解压缩工具,据其官网上发布的数据,全球有超过5亿的用户在使用 2019年2月20日,安全厂商 checkpoint 发布了名为<Extracting a 19 ...

  3. 【学习笔记】 $learn \ from \ failure \ ? ( 雾$

    \(1.\)变量名不要用 \(next\) ,在某些编译器里可能是关键词,可以用 \(nxt\) 代替 \(\\\) \(2.\)在判断某些条件时应该写成 flag = 条件 ? 1 : flag; ...

  4. Springboot:员工管理之登录、拦截器(十(4))

    1:构建登录javaBean com\springboot\vo\LoginUser.java package com.springboot.vo; import lombok.Data; @Data ...

  5. Java 动态编译--DynamicCompiler

    java 动态编译自己写过程的机会比较少,记录一下: package com.xzlf.dynamicCompile; import java.io.IOException; import java. ...

  6. windows下部署.netcore+docker系列二 (unbuntu 18.4 下 安装 docker)亲测!!!

    1.卸载sudo apt-get remove docker docker-engine docker.io containerd runc2.更新sudo apt-get update3.安装依赖包 ...

  7. [Abp vNext 入坑分享] - 前言

    一·背景 Abp vnext是 ABP 框架作者所发起一个完全基于 ASP .NET Core框架,截至2020年4月份已经升级到2.5.0版本,根据经验2.0版本以后可以放心的使用在生产环境.类似a ...

  8. python学习22之函数式编程

    '''''''''1.高阶函数:将函数作为参数传递到另一个函数中,作为这个函数的参数,这样的方式叫高阶函数(1)map:两个参数,一个是函数,一个是iterator,将函数依次作用于Iterator中 ...

  9. 构造最短程序打印自身的 MD5

    一,介绍 比赛题目很简单:构造一个程序,在 stdout 上打印出自身的 MD5,程序越短越好.按最终程序文件大小字节数排名,文件越小,排名越靠前. 只能使用 ld-linux-x86-64.so, ...

  10. 计算4的n次幂html代码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...