HDU1811---Rank of Tetris (拓扑排序+并查集(好题))

来源:互联网 发布:下载资源的软件 编辑:程序博客网 时间:2024/04/30 11:14

题目来源:https://vjudge.net/problem/HDU-1811

题意

大致题意是经过m条信息能否得到全部的排名。若是不能,输出原因,冲突或者是不确定,当冲突和不确定都有时,输出冲突。

思路

感觉这道题最重要的是理解题意,理解‘=’的意思,比如1=2,那么题中有说明:如果两个人具有相同的Rating,那就按这几个人的RP从高到低来排。
这样是否就可以写成:2>1的形式了呢?答案是不能。
如果写成2>1 的形式,那么如果后面有如下信息:
2>3 and 3>1,那么,三条信息能否确定榜单呢?
2>3>1,看着是刚好,但是,第一条信息里,指的是1和2是统一等级的,也就是说,如果2>3,那么1 also >3,也就是发生了冲突,这样叙述就应该清晰明了了、

然后就是用到的算法:并查集+拓扑排序、
首先,根据刚才提到的样例,我们只需要用2去完成: 2>3, 3>1的操作。
因为1=2,所以3>1可以转变成3>2,也就是说可以把相等的点看成一个点,他们与其他点的关系统一用一个点表示,所以才会用到并查集,因为可以把1的父亲记为2。
接着,就是拓扑排序了、
1、在拓扑排序过程中,任意时间内出现超过一个点的入度为0,那么就是不确定。like this:
这里写图片描述
2、除去相等的点个数(因为相等的只需要一个点参加拓扑排序),若是处理的次数小于应该满足的值,那就是存在环,也就是冲突。like this:
这里写图片描述

代码

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#include<queue>using namespace std;vector<int> v_dis[10000+10];//邻接表存图struct pp{    int u,v;    char oper;} str[20000+10];int n,m,num;int In[10000+10];//入度int pre[10000+10];//父亲节点int find(int x){    if(x!=pre[x])    {        int fx=find(pre[x]);        pre[x]=fx;    }    return pre[x];}void solve_sort(){    queue<int> q;    for(int i=0; i<n; i++)    {        if(!In[i]&&pre[i]==i)        {            In[i]=-1;            q.push(i);        }    }    bool flag=0;    while(!q.empty())    {        if(q.size()>1) flag=1;        int w=q.front();        q.pop();        num--;        int len=v_dis[w].size();        for(int i=0; i<len; i++)        {            In[v_dis[w][i]]--;            if(!In[v_dis[w][i]])            {                q.push(v_dis[w][i]);                In[v_dis[w][i]]=-1;            }        }    }    if(num>0) puts("CONFLICT");    else if(flag) puts("UNCERTAIN");    else puts("OK");}int main(){    while(~scanf("%d%d",&n,&m))    {        for(int i=0; i<n; i++)        {            pre[i]=i;            v_dis[i].clear();        }        num=n;//初始化        memset(In,0,sizeof(In));        for(int i=1; i<=m; i++)        {            scanf("%d %c %d",&str[i].u,&str[i].oper,&str[i].v);            if(str[i].oper=='=')            {                int fu=find(str[i].u);                int fv=find(str[i].v);                if(fu!=fv) pre[fv]=fu,num--;//等于一次,就减去一            }        }        for(int i=1; i<=m; i++)        {            if(str[i].oper!='=')            {                if(str[i].oper=='<') swap(str[i].u,str[i].v);                int fu=find(str[i].u);//找到他们的共同的点                int fv=find(str[i].v);                v_dis[fu].push_back(fv);                In[fv]++;            }        }        solve_sort();    }}
原创粉丝点击