update 2017.7.10ios
化學老師讓同窗們出題!昌老師擔任有機組組長!c++
Candy?出了一道數不飽和度的題目,昌老師不會作因此拒絕接受!!!spa
因而Candy?又出了一道用 \(Polya定理\) 數鹵代烴個數的題目,而後把原來這道題扔給了你。code
你有一個有多個環的烷烴的鍵線式,求他的不飽和度。input
值得注意的是,鍵線式的C原子並無標出來,而且線多是直線、斜線或者曲線,上面的C原子數目不定。string
下面有幾個例子,其中X表示線,0表示空:it
1 7
XXXXXXXio
4 7
XXXXXXX
XOOOOOX
XOOOOOX
XXXXXXXclass
最簡單的狀況就是一個4個C的環烷烴,不飽和度爲1.stream
3 7
XXXXX00
0X0X0X0
00XXXXX
這是一個有兩個環的烴,不飽和度是2
它可能張這個樣子
4 7
000X000
00X0X00
0X000X0
0XXXXX0
她的不飽和度是1,樣子自行腦補,我懶得畫了。
輸入一個n行m列的矩陣,X表示線,0表示空,是一個有機物的鍵線式。輸出他的不飽和度
\(n,m < 1000\)
4 7 XXXXXXX XOOOOOX XOOOOOX XXXXXXX
1
下面是題解和標程
最初的想法來自2016.6.26
那時候以爲複雜環式結構的烷烴不飽和度好神奇,從圖論的角度考察了一下,還寫了一篇週記。
一年後作化學題又想到了這個東西,拿着它去考灰哥有沒有忘記個人週記,結果他隨手用了另外一種方法,好快好有趣,貌似正確性有待商榷。我嘗試卡了一下,發現好像只有平面圖成立,而後證實了一下成功了。
後來我發現那就是歐拉公式,而且個人證實和他如出一轍,若是我早出生是否是能夠叫Candy?公式.......
扔定理就跑:
定理1:任意一個烷烴能夠當作無向簡單圖\(G(V,E)\),那麼他的不飽和度爲
\[ \mid E\mid - \mid V\mid +1 \]
其中\(V\)是點集,\(E\)是邊集
定理2:若是由烷烴獲得的圖\(G\)是平面圖,那麼
\[ 它把平面劃分紅的區域數(除去最外圍平面) = \mid E\mid - \mid V\mid +1 \]
平面圖就是能畫在平面上使得邊僅在頂點處相交的圖。
證實去看歐拉公式的吧,不想寫。
這樣一來對於化學題,一眼就看出不飽和度了。
可是出成OI題的話,若是標出C的位置能夠用數分子式的方法很快水過去,因此才變成不肯定C原子,這樣的話就須要獲得上面的定理而後搜一下0組成的連通塊數就行了,當心外圈的0沒有連起來。
大多數人應該不會這個方法吧,昌老師就不會
Candy? : 你怎麼知道這個方法的 (驚恐)
某冰 : 不就應該是這樣嗎 (一臉鄙視)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 105; int n, m, ans; char s[N][N]; int dfc, vis[N][N]; inline bool valid(int x, int y) {return x >= 0 && y >= 0 && x <= n && y <= m && s[x][y] != 'X' && !vis[x][y];} void dfs(int x, int y) { vis[x][y] = dfc; if(valid(x-1, y)) dfs(x-1, y); if(valid(x+1, y)) dfs(x+1, y); if(valid(x, y-1)) dfs(x, y-1); if(valid(x, y+1)) dfs(x, y+1); } int main() { freopen("in", "r", stdin); scanf("%d %d", &n, &m); for(int i=1; i<=n; i++) scanf("%s", s[i]+1); n++; m++; for(int i=0; i<=n; i++) for(int j=0; j<=m; j++) if(s[i][j] != 'X' && !vis[i][j]) dfc++, dfs(i, j); printf("%d", dfc-1); }