1. 程式人生 > >【思維題】【二分圖】TopCoder 12316 —— ThreeColorability

【思維題】【二分圖】TopCoder 12316 —— ThreeColorability

題目傳送門

雖然這道題標籤有個二分圖,實際上只是用來判斷解的.此題的精髓應該是思維的過程

首先利用樣例 (題解),觀察出2*2的格子中,如果有解,那麼解一定為四個一樣或者各兩個的情況.不可能存在三個與一個的情況.也就是說,如果其中三條對角線的方向已經確定了,那麼第四條的方向也是確定的.

將上述的性質轉換為式子就是 cells[x1][y1]cells[x1][y2]cells[x2][y1]cells[x2][y2]=0cells[x1][y1] \bigotimes cells[x1][y2] \bigotimes cells[x2][y1] \bigotimes cells[x2][y2]=0

.其中cells表示當前格子的狀態,0表示N,1表示Z

然後利用異或的性質可以推廣到任意一個矩形上.即如果有解則圖中任意一個矩形都滿足這個式子.
這樣就發現,在有解的條件,任意兩行的狀態要麼是相同的,要麼是相反的.

那麼就下來的事情都簡單了,因為上述的性質,我們可以將所有的約束條件壓到一行裡處理.掃描所有行的每一個位置,如果兩個位置的值不一樣,則連上邊.反之則用並查集維護狀態相同的.這樣處理過後,如果最後存在解,那麼這將是個二分圖,所以利用二分圖染色進行判定即可.

如果有解,那麼可以在染色的時候利用一點貪心的性質,讓0的狀態儘可能在前面.染色完畢後就得到了第一行的狀態.之後行的狀態可以利用當前行和第一行的關係,貪心地推出解.因為已經判斷出了此時是有解的,所以這樣做一定是可以找到解得.

(code by lwc)

#include <bits/stdc++.h>
using namespace std;

class ThreeColorability
{
    static const int MAXN = 50 + 5;

    class
    {
        int fa[ThreeColorability::MAXN];
    public:
        void initialize()
        {
            iota(fa, fa + ThreeColorability::MAXN, 0);
        }

        int
find(int x) { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } void merge(int x, int y) { // cerr << "Merge " << x << " " << y << endl ; fa[find(x)] = find(y); } } disjointSet; struct edge; typedef struct edge * pEdge; struct edge { int to; pEdge nxt; } E[MAXN * MAXN * 4]; int eCnt; int N, M; int vis[MAXN]; int a[MAXN][MAXN]; bool adjMat[MAXN][MAXN]; pEdge head[MAXN]; void addEdge(int u, int v) { // cerr << "Edge added :" << u << " " << v << endl ; pEdge p; p = &E[eCnt++]; p->nxt = head[u], head[u] = p; p->to = v; p = &E[eCnt++]; p->nxt = head[v], head[v] = p; p->to = u; } bool isBipartite = true; void DFS(int x, int col) { if (vis[x] >= 0) { // cerr << "Revisited " << x << " " << col << " " << vis[x] << endl ; if (vis[x] != col) isBipartite = false; return; } vis[x] = col; for (pEdge p = head[x]; p; p = p->nxt) DFS(p->to, col ^ 1); } public: ThreeColorability() { eCnt = 0; N = 0, M = 0; memset(vis, 0xFF, sizeof vis); memset(head, 0x00, sizeof head); memset(adjMat, 0x00, sizeof adjMat); disjointSet.initialize(); } vector<string> lexSmallest(vector<string> cells) { vector<string> answer = cells; N = cells.size(), M = cells[0].length(); for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) switch (cells[i][j]) { case '?': a[i][j] = -1; break; case 'N': a[i][j] = 0; break; default: a[i][j] = 1; } for (int i = 1; i < N; i++) for (int j = 0; j < M; j++) for (int k = j + 1; k < M; k++) if ((~a[i][j]) && (~a[i][k])) { if (a[i][j] ^ a[i][k]) adjMat[j][k] = adjMat[k][j] = 1; else disjointSet.merge(j, k); } for (int i = 0; i < M; i++) for (int j = i + 1; j < M; j++) if (adjMat[i][j]) addEdge(disjointSet.find(i), disjointSet.find(j)); for (int i = 0; i < M; i++) if (~a[0][i]) DFS(disjointSet.find(i), a[0][i]); for (int i = 0; i < M; i++) if (vis[disjointSet.find(i)] < 0) DFS(disjointSet.find(i), 0); if (!isBipartite) return vector<string> { }; for (int i = 0; i < M; i++) a[0][i] = vis[disjointSet.find(i)]; for (int i = 1; i < N; i++) { bool vist[2] = { 0 }; for (int j = 0; j < M; j++) if (~a[i][j]) vist[a[i][j] ^ a[0][j]] = 1; if (!vist[0] && !vist[1]) vist[a[0][0]] = 1; if(vist[0]) for(int j = 0; j < M; j++) a[i][j] = a[0][j]; else for(int j = 0; j < M; j++) a[i][j] = a[0][j] ^ 1; } for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) answer[i][j] = (a[i][j] ? 'Z' : 'N'); return answer; } };

相關推薦

思維二分TopCoder 12316 —— ThreeColorability

題目傳送門 雖然這道題標籤有個二分圖,實際上只是用來判斷解的.此題的精髓應該是思維的過程 首先利用樣例 (題解),觀察出2*2的格子中,如果有解,那麼解一定為四個一樣或者各兩個的情況.不可能存在三個與一個的情況.也就是說,如果其中三條對角線的方向已經確定了,那麼

思維AGC004F Namori

分析: 比較複雜的一道思維題。。。 先考慮樹的情況,把所有點按照深度的奇偶性分為兩類,在所有深度為奇的點放一個“+1”,在所有深度為偶的點放一個“-1”。這樣一來,每次染色,就可以看作交換了一對相鄰的“+1”和“-1”。目標狀態就是所有的“+1”移動到“-1”所

二分洛谷P1640連續攻擊遊戲

接下來 真的是 str style 並且 一行 include can div 題目描述 lxhgww最近迷上了一款遊戲,在遊戲裏,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每

二分ZJOI2007小Q的遊戲

格子 scan clas ecn 輸出 每次 他還 顏色 sed 660. [ZJOI2007] 小Q的矩陣遊戲 ★☆ 輸入文件:qmatrix.in 輸出文件:qmatrix.out 簡單對比 時間限制:1 s 內存限制:128 MB 【問題描述】

UVa 679 - Dropping Balls二叉樹思維

get title lld -s round () color 直接 2個 題目鏈接 題目大意: 小球從一棵所有葉子深度相同的二叉樹的頂點開始向下落,樹開始所有節點都為0。若小球落到節點為0的則往左落,否則向右落。並且小球會改變它經過的節點,0變1,1變0。給定樹的深度

二分二分的多重匹配

pat 元素 () pre AI find main 尋找 ++ 某些問題中,會遇到一對多的二分圖模型,即允許集合Y中的一個元素和集合X中的多個元素匹配(通常有一個最大限制n) /*二分圖多重匹配算法*/ const int MAXN=1001;//最大頂點數 i

jzo5934. NOIP2018模擬10.29列隊(二分匹配)

5934. 【NOIP2018模擬10.29】列隊 Description Sylvia是一個熱愛學習的女孩子。 在平時的練習中,他總是能考到std以上的成績,前段時間,他參加了一場練習賽,眾所周知,機房是一個 的方陣。這天,他又打爆了std,感到十分無聊,便想要hack機房內同學的

思維 kmp 構造bzoj4974: [Lydsy1708月賽]字串大師

字串思博題這一塊還是有點薄弱啊。 Description 一個串T是S的迴圈節,當且僅當存在正整數k,使得S是T^k(即T重複k次)的字首,比如abcd是abcdabcdab的迴圈節 。給定一個長度為n的僅由小寫字元構成的字串S,請對於每個k(1<=k<=n

CodeForces 1072C Cram Time思維

傳送門:http://codeforces.com/problemset/problem/1072/C C. Cram Time time limit per test 1 second memory limit per test 256 megabytes input

HDU 1045 Fire Net 連通塊的壓縮 二分匹配

題目:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav

BZOJ1345 Baltic2007 序列問題Sequence 思維*

BZOJ1345 Baltic2007 序列問題Sequence Description 對於一個給定的序列a1,…,an,我們對它進行一個操作reduce(i),該操作將數列中的元素ai和ai+1用一個元素max(ai,ai+1)替代,這樣得到一個

二分bzoj1059 矩陣遊戲

 行列作為點  行為左部 列為右部 黑色格點表示從左部向右部連邊   使左上角到右下角的連線上的格子均為黑色 一個行只能和一個列連邊  相當於匹配 顯然每種完美匹配對應了一個方案 並不需要考慮如何調換和調換行列後方陣是什麼樣的   從而降低時間複雜度 #include

BZOJ4025: 二分

題解 lct維護一個結束時間作為邊權的最大生成樹,每次出現奇環就找其中權值最小的那條邊,刪掉的同時還要把它標記上,直到這條邊消失 如果有標記則輸出No 邊權通過建立虛點來維護 程式碼 #include <bits/stdc++.h> #define fi first #define se

網路流/二分Gym

題意: 有m個插座,n個電器,每個插座最多可連線一個電器。另外有一個插頭,可以使得一個插座連線三個電器,問最大匹配數是多少。 題解: 我是寫的網路流,先跑一遍容量都為1的dinic,然後列舉插座多給兩個容量,在殘餘網路中跑。每一次的列舉都需要把上一次的流量退回,可以

思維貪心模擬CodeForces794 C Naming Company

【題意】 兩個人A和B在玩一個填字母遊戲。現在A和B都有一個包含 n 個小寫字母的多重集合(可以有重複字元)。 初始有一個長度為n的空字串s,兩人輪流操作,A先手。一次操作可以將自己集合中的一個字母拿出來,放到字串s的某個空位置,然後把這個字母從自己集合中刪除(如果

二分找最大流、最小獨立集、匈牙利演算法

                                   Asteroids Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1

離線 線段樹分治bzoj4025: 二分

昨天mac的gdb掛了,今天怎麼筆記本的gdb也掛了…… Description 神犇有一個n個節點的圖。因為神犇是神犇,所以在T時間內一些邊會出現後消失。神犇要求出每一時間段內這個圖是否是二分圖。這麼簡單的問題神犇當然會做了,於是他想考考你。 Input 輸

BZOJ 1854: [Scoi2010]遊戲 二分並查集

Description lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgw

bzoj1854二分

第一次做的時候居然沒看出來二分圖。。一直想資料結構。。。中毒太深。。#include <cstdio> #include <cstring> #include <iostr

hdu 2063 過山車二分

題目連結 思路:二分圖匹配 匈牙利演算法(個人理解最優匹配):每次查詢都儘可能匹配,如果這個點的物件已經被匹配了,那就遞迴拆邊,遞迴這個過程保證拆後的點都能匹配才能夠回溯,否則不匹配,開始下一個