HDU Rank of Tetris
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1811
题意:中文问题就不解释题意了。
这道题其实就是一个拓扑排序判圈,我的博客里面其他几篇拓扑排序判圈的套路一样。但是这道题与他们不同的的是在大小关系里面存在一种 “=”的关系,这就意味的那些序号不同的点,实际上是一个点。共享入度和出度。我们可以通过并查集将他们合并,合成一个点。这里说一下如何判断信息不完全。我们早先在做拓扑排序,多种排列方式的时候,按照字典序输出。我们建立一个优先队列,维护字典序,这个时候堆里是有很多元素的,我们通过优先队列取出最小或者最大,实际上这些元素在拓扑排序中是等价关系,也就是说他们之间的大小关系无法比较。在这道题中,如果滞留在队列中的元素超过一个说明有两个元素无法比较的,就说明了答案是UNCLEARED。直接看代码吧!,具体细节写在注释里面了。
//Author: xiaowuga #include <bits/stdc++.h> #define maxx INT_MAX #define minn INT_MIN #define inf 0x3f3f3f3f const long long N=10000+10; using namespace std; typedef long long LL; vector<int>p[N]; int f[N]; int in[N]; struct node{ int x,y; char ch; }oj[N]; int n,m; int ct=0,flag=0; //并查集套路 int Find(int x){ return f[x]==x?x:f[x]=Find(f[x]); } void topo(){ queue<int>q; while(!q.empty()) q.pop(); for(int i=0;i<n;i++) if(!in[i]&&Find(i)==i) q.push(i);//首先得是并查集中的根,然后出度为0 while(!q.empty()){ if(q.size()>1) flag=1;//同级元素大于一个说明有至少有两个元素无法比较,所以信息不完全 int t=q.front();q.pop(); ct++; for(int i=0;i<p[t].size();i++){ int tmp=p[t][i]; if(--in[tmp]==0) q.push(tmp); } } if(ct!=n) cout<<"CONFLICT"<<endl; else if(flag) cout<<"UNCERTAIN"<<endl; else cout<<"OK"<<endl; } int main() { ios::sync_with_stdio(false);cin.tie(0); while(cin>>n>>m){ for(int i=0;i<n;i++) f[i]=i; memset(in,0,sizeof(in)); for(int i=0;i<n;i++) p[i].clear(); int x,y; ct=flag=0; //先处理‘=‘带来的点的减少,建立并查集缩点 for(int i=0;i<m;i++){ cin>>oj[i].x>>oj[i].ch>>oj[i].y; if(oj[i].ch==‘=‘){ x=Find(oj[i].x); y=Find(oj[i].y); if(x!=y) {f[x]=y;ct++;}//缩点了别忘了ct++,因为相当于总点数减少了一个 } } //根据缩完点的点边关系,反向建图(正向建图也可以) for(int i=0;i<m;i++){ if(oj[i].ch==‘=‘) continue; x=Find(oj[i].x); y=Find(oj[i].y); if(oj[i].ch==‘>‘){ p[y].push_back(x); in[x]++; } else{ p[x].push_back(y); in[y]++; } } //并查集处理完建图之后就是常规的拓扑排序 topo(); } return 0; }
在最小生成树的克鲁斯卡尔算法里,并查集被用来判断是否形成环路,正如我在我的其他几份博文里面说的那样,我认为在一个图中,如果出现环,那么环可以缩成一个点。环上的点实际上是等价的,也就是说并查集实际上是通过边的关系,说明两个不同的点,合并成一个点,通过一个根共享他们的信息。a=b全等价于a>b,a<b这样两条边。我们根据这个信息把a,b合并。通过一个根可以是a,也可以是b来查询这个整体的信息。总结一句并查集就是把一些不同的东西合并在一起,一起查询的工具。
时间: 2024-11-05 20:48:49