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); }