【建图+拓扑判环】BZOJ3953: [WF2013]Self-Assembly

Description

自动化学制造(Automatic Chemical Manufacturing,简称ACM)正在对一个叫自组装(self-assembly)的过程进行实验。在这个过程中,有着天然相互吸引力的分子被混合在溶液中,任由它们聚集组合成更大的结构。但是有一个问题随之出现:有时候,分子们会把自身组合成一个无限大的结构体,以至于把容器撑爆。
 
  你需要写一个程序来判断一个给定的分子集合是否可能组合成一个无限大的结构体。为了使问题简化,你可以作以下两个假设:
  1. 问题被限制在二维平面上。
  2. 分子集合中的每个分子都被表示成一个正方形。其中正方形的四条边分别代表分子间相连接的四个表面。
 
  你将从数据中得到每种分子的描述。每种分子有四个连接标识来分别表示每条边能与另外分子的哪种边相连。连接标识有两种:
  ● 一个大写字母(A,…,Z)加上一个 ‘+’ 号或一个 ‘-’ 号。两条边能并在一起当且仅当两者的字母相等且符号相反。比方说,‘A+’ 与 ‘A-’ 兼容,但与 ‘A+’ 或 ‘B-’ 不兼容
  ● 两个零 ‘00’。这条边将不和任意一条边兼容(包括‘00’)。
 
  假设每种分子都有无限个,并且每个分子都可以旋转和翻转。当分子将自身组成一个结构体时,相互贴合的边必须能够相互兼容,当然,无论边的连接标识是什么,它都可以不与另外边贴合。
 
  图 1 是一个由三种分子组成的一个有限的结构体(它们也有可能组成另外的有限结构体)。
 

Solution

这道题关键是要想到怎么建图

把元素看做点

正方形是使这些点联系的媒介也就是边

a和b是一个正方形上两个元素

那么a可以通过b到op(b)

就这么建图,对于无穷大这种设问,显然是问有无环

对于有向图,拓扑排序即可

存在环就可以理解为它们总是可以通过旋转翻折拼在一起(想想只往下或右拼)

大概比较神奇

紫书例题

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=55;
 5 
 6 int r[maxn],del[maxn],G[maxn][maxn];
 7 char s[10];
 8 int n,a[5];
 9 
10 int idx(int p){
11     if(s[p*2]=='0') return -1;
12     int ret=s[p*2]-'A';
13     ret*=2;
14     if(s[p*2+1]=='-') ret++;
15     return ret;
16 }
17 
18 int topu(){
19     for(int t=0;t<52;t++){
20         int flag=0;
21         for(int i=0;i<52;i++)
22             if(!del[i]&&!r[i]){
23                 del[i]=1;
24                 for(int j=0;j<52;j++)
25                     if(G[i][j]) r[j]--;
26                 flag=1;
27                 break;
28             }
29         if(!flag) return 0;
30     }
31     return 1;
32 }
33 
34 int main(){
35     scanf("%d",&n);
36     for(int i=1;i<=n;i++){
37         scanf("%s",s);
38         for(int j=0;j<4;j++)
39             a[j]=idx(j);
40         
41         for(int j=0;j<4;j++)
42             for(int k=j+1;k<4;k++)
43             if(a[j]!=-1&&a[k]!=-1&&j!=k){
44                 if(!G[a[j]][a[k]^1]) r[a[k]^1]++;//一开始少了if以至于入度比实际的大
45                 G[a[j]][a[k]^1]=1;
46                 if(!G[a[k]][a[j]^1]) r[a[j]^1]++;
47                 G[a[k]][a[j]^1]=1;
48             }
49     }
50     
51     if(topu()) printf("bounded");
52     else printf("unbounded");
53     return 0;
54 }
原文地址:https://www.cnblogs.com/xkui/p/4569566.html