[NOI2015]程序自动分析

题目链接

https://www.luogu.org/problemnew/show/P1955

题解

毫无悬念,这是一道签到题

如果把所有变量看作一个点,那么相等关系就是在这两个点之间连一条边,而不等关系不与相等关系矛盾的必要条件则是:两个点不能处在同一集合中。

于是我们可以用并查集来维护这样的一个系统:如果给出一个相等关系,就合并两个集合,将所有的不等关系存储起来,在最后处理不等关系,如果两个点处于同一集合,那么这样的不等关系就不能满足。

PS:由于变量下标的范围达到了10^9,所以可以运用hash(map?)将下标映射到1-2*10^5的范围以内再进行处理。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <map>
 4 #include <cstring>
 5 using namespace std;
 6 map<int,int> num;
 7 int fa[200005];
 8 int tj[100005][2];
 9 int find(int a)//用递归写会爆栈,所以这里用非递归写了 
10 {
11  int r=a;
12  while(r!=fa[r])
13   r=fa[r];
14  int i=a,j;
15  while(i!=r)
16  {
17   j=fa[r];
18   fa[i]=r;
19   i=j;
20  }
21  return r;
22 }
23 void unionn(int i,int j)
24 {
25  fa[j]=i;
26 }
27 void setfa()
28 {
29  for(int i=1;i<=200000;i++)
30   fa[i]=i;
31 }
32 int main()
33 {
34  int t;
35  scanf("%d",&t);
36  while(t--)
37  {
38   int cnt=0,cntt=0;
39   num.clear();
40   memset(tj,0,sizeof(tj));
41   setfa();
42   int n;
43   scanf("%d",&n);
44   for(int k=1;k<=n;k++)
45   {
46    int i,j,e;
47    scanf("%d%d%d",&i,&j,&e);
48    if(num[i]==0)num[i]=++cnt;//map大法好,但常数确实大了 
49    if(num[j]==0)num[j]=++cnt;//可以试试unordered_map? 
50    if(e)unionn(find(num[i]),find(num[j]));
51    else
52    {
53        cntt++;
54     tj[cntt][0]=num[i];
55     tj[cntt][1]=num[j];
56    }
57   }
58   int flag=1;
59   for(int i=1;i<=cntt;i++)
60    if(find(tj[i][0])==find(tj[i][1]))
61    {
62        puts("NO");
63        flag=0;
64        break;
65    }
66   if(flag)puts("YES");
67  }
68  return 0;
69 }
View Code

猜你喜欢

转载自www.cnblogs.com/StudyingFather/p/8992012.html