【HDU 1811】 Rank of Tetris 並查集+拓撲
阿新 • • 發佈:2018-11-15
題目連結:傳送門
中文題目就不闡述題意了,我最開始的想法是種類並查集,但是細想一下,發現並不可行,因為題目沒有告訴有多少型別。
做法:關鍵問題是處理等號的兩個點,其實兩個點相等,就相當於這兩個人的排名是一樣的,我們用並查集搞定這麼些個相等排名的點,之後把有全序關係的點入度入圖,然後拓撲排序走一發,如果到最後所有點的度都變成了0,那麼這個圖就滿足OK的條件,否則屬於衝突。如果最後所有點的度都變成了0,但是拓撲排序期間有兩個點同時度為0,那麼說明資訊不夠全。
①先用並查集將相等的關係合併
int n,m; while(~scanf("%d %d",&n,&m)) { int ind[10005]= {0},peo=m; ///最終判斷能否去掉所有邊。(最終所有點的入度都為0) bool vis[10005]= {0}; vector<int>load[10005]; for(int i=0; i<n; i++) p[i]=i; for(int i=1; i<=m; i++) { scanf("%d %c %d",&text[i].s,&text[i].re,&text[i].e); if(text[i].re=='=') { peo--; ///相等的邊去掉,其沒有意義 p[f(text[i].s)]=f(text[i].e); ///讓所有相等的點(排名相同的人),用一個人代替。 } }
②利用關係入度
for(int i=1; i<=m; i++) { int x=f(text[i].s); int y=f(text[i].e); if(text[i].re=='>') { load[x].push_back(y); ind[y]++; } if(text[i].re=='<') { load[y].push_back(x); ind[x]++; } }
③拓撲排序+輸出判斷
queue<int>ranks; ///BFS拓撲 int sign=0;///入度為0的點最多一個 int ff1=1; ///判斷變數 sign for(int i=0; i<n; i++) { if(!vis[i]&&f(i)==i&&ind[i]==0)///入隊的條件 { sign++; vis[i]=1; ranks.push(i); } } if(sign>1) ff1=0; while(ranks.size()) { sign=0; int w=ranks.front(); ranks.pop(); int d=load[w].size(); for(int i=0; i<d; i++) { peo--; ///有關係的邊去除。 int e=load[w][i]; ind[e]--; ///入度減 1 if(!vis[e]&&f(e)==e&&ind[e]==0) { sign++; vis[e]=1; ranks.push(e); } } if(sign>1) ff1=0; } if(peo!=0) ///判斷條件 printf("CONFLICT\n"); else if(ff1==0) printf("UNCERTAIN\n"); else printf("OK\n");
完整的程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<set>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct node
{
int s;
char re;
int e;
} text[20005];
int p[10005];
int f(int x)
{
return p[x]==x?x:p[x]=f(p[x]);
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
int ind[10005]= {0},peo=m; ///最終判斷能否去掉所有邊。(最終所有點的入度都為0)
bool vis[10005]= {0};
vector<int>load[10005];
for(int i=0; i<n; i++)
p[i]=i;
for(int i=1; i<=m; i++)
{
scanf("%d %c %d",&text[i].s,&text[i].re,&text[i].e);
if(text[i].re=='=')
{
peo--; ///相等的邊去掉,其沒有意義
p[f(text[i].s)]=f(text[i].e); ///讓所有相等的點(排名相同的人),用一個人代替。
}
}
for(int i=1; i<=m; i++)
{
int x=f(text[i].s);
int y=f(text[i].e);
if(text[i].re=='>')
{
load[x].push_back(y);
ind[y]++;
}
if(text[i].re=='<')
{
load[y].push_back(x);
ind[x]++;
}
}
queue<int>ranks; ///BFS拓撲
int sign=0;///入度為0的點最多一個
int ff1=1; ///判斷變數 sign
for(int i=0; i<n; i++)
{
if(!vis[i]&&f(i)==i&&ind[i]==0)///入隊的條件
{
sign++;
vis[i]=1;
ranks.push(i);
}
}
if(sign>1)
ff1=0;
while(ranks.size())
{
sign=0;
int w=ranks.front();
ranks.pop();
int d=load[w].size();
for(int i=0; i<d; i++)
{
peo--; ///有關係的邊去除。
int e=load[w][i];
ind[e]--; ///入度減 1
if(!vis[e]&&f(e)==e&&ind[e]==0)
{
sign++;
vis[e]=1;
ranks.push(e);
}
}
if(sign>1)
ff1=0;
}
if(peo!=0) ///判斷條件
printf("CONFLICT\n");
else if(ff1==0)
printf("UNCERTAIN\n");
else
printf("OK\n");
}
return 0;
}