判斷二分圖
阿新 • • 發佈:2020-07-15
染色法
例題 1
解: 判斷是否為二分圖即可 ,同時可能有多個連通圖 ,需要多次搜尋染色 .
示例程式碼 1
說明: 鄰接矩陣存圖 ,dfs搜尋染色 .
時間 4704MS ... 題目給了10000MS 管他呢 .
//#include <bits/stdc++.h> #include <stdio.h> #include <string.h> #include <iostream> #define LL long long #define Pi acos(-1.0) #define INF 2147483646 #define eps 1e-9 #define MS 2009 #define mss 17 using namespace std; // Notice the data size // Notice the input and output int n,m,k,u,v,flag; int mp[MS][MS]; int col[MS]; void dfs(int bt){ if(flag) return; for(int i=1;i<=n;i++){ if(mp[bt][i]){ if(col[i] == col[bt]){ flag = 1; return; } else if(col[i] == -1){ col[i] = !col[bt]; dfs(i); } } } } int main() { ios::sync_with_stdio(false); cin >> k; for(int o=1;o<=k;o++){ memset(mp,0,sizeof mp); memset(col,-1,sizeof col); flag = 0; cin >> n >> m; for(int i=1;i<=m;i++){ cin >> u >> v; mp[u][v] = mp[v][u] = 1; } for(int i=1;i<=n;i++){ if(col[i] == -1){ col[i] = 0; dfs(i); } } if(flag){ cout << "Scenario #" << o << ":" << endl; cout << "Suspicious bugs found!" << endl; cout << endl; } else{ cout << "Scenario #" << o << ":" << endl; cout << "No suspicious bugs found!" << endl; cout << endl; } } return 0; }
示例程式碼 2
說明: 鏈式前向星存圖 ,dfs搜尋染色 .
時間 4407MS... 和鄰接矩陣差不了多少 ,就當再練一次吧 .
//#include <bits/stdc++.h> #include <stdio.h> #include <iostream> #define LL long long #define Pi acos(-1.0) #define INF 2147483646 #define eps 1e-9 #define MS 2009 #define mss 17 using namespace std; // Notice the data size // Notice the input and output int n,m,k,u,v,flag,tot; int col[MS]; struct node{ int to,ne; }edge[2000009]; int head[MS]; void add(int u,int v){ edge[tot].to = v; edge[tot].ne = head[u]; head[u] = tot++; } void dfs(int bt){ if(flag) return; for(int i=head[bt];i!=-1;i=edge[i].ne){ int it = edge[i].to; if(col[it] == col[bt]){ flag = 1; return; } else if(col[it] == -1){ col[it] = !col[bt]; dfs(it); } } } int main() { ios::sync_with_stdio(false); cin >> k; for(int o=1;o<=k;o++){ for(int i=0;i<MS;i++) col[i] = head[i] = -1; flag = tot = 0; cin >> n >> m; for(int i=1;i<=m;i++){ cin >> u >> v; add(u,v); add(v,u); } for(int i=1;i<=n;i++){ if(col[i] == -1){ col[i] = 0; dfs(i); } } if(flag){ cout << "Scenario #" << o << ":" << endl; cout << "Suspicious bugs found!" << endl; cout << endl; } else{ cout << "Scenario #" << o << ":" << endl; cout << "No suspicious bugs found!" << endl; cout << endl; } } return 0; }
例題 2
題意: k 組樣例 ,每次給出 n 個頂點 m 條邊的無向圖 ,將整個圖的所有頂點填充數字 ,每個頂點 u 可填數字 1,2,3 . 要求 m 條邊每條邊連線的兩個頂點 (u,v) 的填充的數字權值之和為奇數 .問這樣的填充方法有多少個 .方案可能很大,取模998244353 .
如果沒有則輸出0.
解: 先將其分為二分圖 ,得到兩個集合 X ,Y ,當 X 中填 2 此時 Y 中每個點都有 1 3 兩種選擇 ,所以有 2^y 種 . 反過來 Y 填 2 則有 2^x 種 ,所以每一個連通圖都有 2^x + 2^y 種 . 可能出現多個連通圖 ,累乘即可 .
注意要對 2 的次方作打表處理 ,當時傻傻的用快速冪超時 ...
示例程式碼
#include <bits/stdc++.h>
#define LL long long
#define Pi acos(-1.0)
#define INF 2147483646
#define eps 1e-9
#define MS 300009
#define mss 17
#define mod 998244353
using namespace std;
// Notice the data size
// Notice the input and output
LL n,m,k,u,v,flag,cx,cy;
LL col[MS],er[MS];
struct node{
LL to,ne;
}edge[MS<<1];
LL head[MS],tc;
void add(LL a,LL b){
edge[tc].to = b;
edge[tc].ne = head[a];
head[a] = tc++;
}
void dfs(LL bt,LL cc){ // bfs也行
if(flag) return;
for(int i=head[bt];i!=-1;i=edge[i].ne){
LL tt = edge[i].to;
if(col[tt] == col[bt]){
flag = 1;
return;
}
else if(col[tt] == -1){
col[tt] = !cc;
if(col[tt] == 0) cx++; // x 集合元素個數++
else cy++; // y 集合元素個數++
dfs(tt,!cc);
}
}
}
int main() {
ios::sync_with_stdio(false);
er[0] = 1;
for(int i=1;i<MS;i++){ // 2 的次方
er[i] = er[i-1]*2LL%mod;
}
cin >> k;
while(k--){
flag = 0;
LL ans = 1;
cin >> n >> m;
for(int i=0;i<=n;i++){
head[i] = col[i] = -1;
}
for(int i=1;i<=m;i++){ // 鏈式前向星
cin >> u >> v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++){ // 也許有多個連通圖
if(col[i] == -1){
cx = cy = 0;
cx++; // 記錄 X 集合元素個數
col[i] = 0;
dfs(i,0);
if(flag) break;
ans = ans*(er[cx]+er[cy])%mod;
}
}
if(flag) cout << 0 << endl;
else cout << ans << endl;
}
return 0;
}