产生冠军 HDU - 2094(连通/树/思维)
题意:有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。
分析:以下两种思路。
- 连通 + 入度为 0 的点只有一个:就可以确定冠军;否则不可以。
- 思维:确定冠军,那么依据胜利关系可以建立一棵树,根节点作为冠军。
按照树的节点数与边数的关系:n = m+1,
也就是总人数 = 失败的人数 + 1.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2010, INF = 0x3f3f3f3f;
int n, m,d[N];
string a, b;
map<string, int> hs;
map<int, string> rhs;
vector<int> g[N];
bool st[N];
bool bfs() {
memset(st, 0, sizeof(st));
queue<string> q;
for (auto u : hs)
if (d[u.second] == 0)
q.push(u.first);
if (q.size() > 1) return 0;
int cnt = 0;
while (q.size()) {
string u = q.front(); q.pop();
cnt++;
for (auto v : g[hs[u]]) {
if (!st[v])
q.push(rhs[v]), st[v] = 1;
}
}
return cnt == m;
}
int main() {
while (cin >> n && n) {
for (int i = 1; i <= n; i++) {
cin >> a >> b;
if (!hs.count(a)) hs[a] = ++m, rhs[m] = a;
if (!hs.count(b)) hs[b] = ++m, rhs[m] = b;
g[hs[a]].push_back(hs[b]), d[hs[b]]++;
}
if (bfs()) cout << "Yes\n";
else cout << "No\n";
for (int i = 0; i <= m; i++) g[i].clear(), d[i] = 0;
hs.clear(), rhs.clear(), m = 0;
}
return 0;
}
int main2() {
while (cin >> n && n) {
set<string> s1, s2;
for (int i = 1; i <= n; i++) {
cin >> a >> b;
s1.insert(a), s1.insert(b);
s2.insert(b);
}
if (s1.size() == s2.size() + 1) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}