牛客网 【每日一题】4月23日题目精讲 边的染色
鏈接:
時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld題目描述
小團有一張n個點,m條邊的無向圖G,有些邊上已經被標記了0或1,表示它的邊權。 現在你需要給剩下的邊標記邊權為0或1,求有幾種標記的方式滿足: 對于G中任意一個環,里面所有邊的邊權的異或值為0。 環的定義如下: 對于任意k(k≥2)個點{a1,a2,...,ak},若對于所有的i<k滿足ai與ai+1之間有邊,且a1=ak成立,則這k個點構成一個環。輸入描述:
第一行兩個整數n, m。
接下來m行,每行3個整數u, v, w,表示有一條邊(u,v),若w=-1則這條邊上沒有標記,否則w=0或1表示這條邊上標記了w。
數據保證沒有重邊和自環。
1≤n≤100,000 0≤m≤min(n*(n-1)/2, 100000)
輸出描述:
輸出方案數對998,244,353取模的值。
示例1
輸入
3 3
1 2 -1
2 3 -1
3 1 -1
輸出
4
題解:
看了鄧老師的題解,恍然大悟,感謝大佬講解
一下為我結合鄧老師所理解的:
首先思考:一個連通圖(圖中任意兩點都是連通的),給邊標上0和1,使得任意一個環的所有邊的異或和為0,問有多少種方案?
異或:相同為0,不同為1
題目要求我們給邊賦值,但是邊賦值很不方便,我們就看看選擇給點賦值,為什么?因為邊和點是共存的,特別是在一個環中,每個點都貢獻了兩個邊,那我們就可以把這個邊的值當做是邊兩端頂點的值的異或,一個環有m個點,m條邊,異或m條邊就等于將m個點都異或兩次。相同為0,那么異或兩次相同的值結果一定為0.那點就可以隨意賦值
對于一個連通塊:
將所有點的數都 ^ 1(也就是0變成1,1變成0),兩點異或出來的邊值并未發生改變(就相當于原本1 ^ 1 改成0 ^ 0,結果不變),n個點每個點都是有兩個方案的(即0或1),那么給點賦值的方案也就是2n個,對應的邊賦值方案是點的方案除以2,所以n個點的連通圖有2n-1種方案。
對于不是一個連通圖:
我們可以求分散的每個連通圖種類,然后乘一起就可
但是原本題目中是存在有些邊一開始就賦好值,我們可以從提前標好的邊開始出發找連通塊,不然到最后你自己標記的很有可能和題目給你不適配,又要重新改。在存有題目給的邊的這個連通塊里,我們只需要確定一個點的權值,其他部分也可以因此確定。如果把這個連通塊大小記作ki,那么這個連通塊的存在就會使得方案數需要在原來的基礎上(不考慮之前有標記)除以2 ki-1,因為其他點不能自由選。
還有:題目給你的數據本身可能就是矛盾,判定遠直接輸出0
我盡量只能理解到這份上。。
借鑒其他大佬的代碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 3; const int mod = 998244353; int f[maxn], col[maxn]; vector<pair<int,int> > edge[maxn]; bool flag; int find(int x){return f[x] == x ? x : f[x] = find(f[x]); } void dfs(int u, int p){//染色過程if (!flag) return;for (int i = 0; i < edge[u].size(); ++i){int v = edge[u][i].first, w = edge[u][i].second;if (col[v] == -1){col[v] = col[u]^w;dfs(v, u);}else if (col[u]^col[v] != w){flag = 0;return;}} } int main(void){int n, m,ans; int u, v, w;scanf("%d%d",&n,&m);for (int i = 1; i <= n; ++i) f[i] = i;ans = n;for (int i = 1; i <= m; ++i){cin >> u >> v >> w;if (find(u) != find(v)){ans--;f[find(u)] = find(v);/}if (w != -1){edge[u].push_back(make_pair(v, w));edge[v].push_back(make_pair(u, w));}}memset(col, -1, sizeof col);int cnt = 0;flag = 1;for (int i = 1; i <= n; ++i){if (col[i] == -1){col[i] = 0;dfs(i, i);cnt++;}}if (!flag){cout << 0 << endl; return 0;}ll ans = 1;for (int i = 0; i < cnt-ans; ++i) ans = ans*2%mod;cout << ans << endl;return 0; }總結
以上是生活随笔為你收集整理的牛客网 【每日一题】4月23日题目精讲 边的染色的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 牛妹的游戏
- 下一篇: 炉石传说盗贼(潜行者)卡牌组合技巧与攻略