链接:https://ac.nowcoder.com/acm/contest/5673/I
来源:牛客网
题目描述
Apollo is playing an interesting computer game. There are
N
N
N rounds in the game.
At each round, the computer will give Apollo two integers (
a
i
a_i
ai and
b
i
b_i
bi), and Apollo can do exactly one of the following three actions.
Apollo can do nothing.
If integer
a
i
a_i
ai has not been selected in all previous rounds, Apollo can select integer
a
i
a_i
ai.
If integer
b
i
b_i
bi has not been selected in all previous rounds, Apollo can select integer
b
i
b_i
bi.
Apollo has cracked the game, and he has known all the candidate numbers of each round before the game starts. Now he wants to know the maximum number of integers he can select with the optimal strategy.
I believe it would be very simple question for you, please help Apollo solve this question.
输入描述:
The first line is an integer
T
\mathbf{T}
T (
1
≤
T
≤
10
1 \leq \mathbf{T} \leq 10
1≤T≤10), which is the number of test cases.
Each test case begins with a line containing a positive integer N N N ( 1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1≤N≤105), indicating the number of rounds in this game.
Then
N
N
N lines follow. The
i
i
i-th line contains two integers
a
i
a_i
ai and
b
i
b_i
bi (
1
≤
a
i
≤
1
0
9
1 \le a_i \le 10^9
1≤ai≤109,
1
≤
b
i
≤
1
0
9
1 \le b_i \le 10^9
1≤bi≤109), indicating that two integers of the
i
i
i-th round.
输出描述:
For each test case, output one line containing Case #x: y'
, where
x
x
x is the test case number and
y
y
y is the answer.
示例1
输入
2
6
1 2
2 3
3 4
1 4
1 3
2 4
5
1 2
1 2
1 3
2 3
5 6
输出
Case #1: 4
Case #2: 4
首先,根据贪心原则,如果一个数只出现过一次,那么选这个数的结果一定不会变差。因为选这个只出现过一次的数会使总数加
1
1
1并且至多会使
1
1
1个数在之后不能被选择,也就是对应位置的另一个数且这个数在之前没被选过,在该位置之后不会再出现。但是如果选择这个不能被选的数情况和选只出现过一次的数一样,而什么都不选情况只会变差。
然后,如果序列里面所有的数都出现了至少两次,那么总存在一种选择方式使得每种数都能被选到。因为不可能通过选择一个数使得另一个数不能被选到。
以上策略可以通过拓扑排序实现,即先选只出现一次的,如果选择一个数导致另一个数只能被选一次,那么把另一个数入队。最后剩下的数都是出现多次的,在答案的基础上加上剩下的数的数量即可。
#include<bits/stdc++.h>
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;
inline int qr() {
int f = 0, fu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')fu = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
f = (f << 3) + (f << 1) + c - 48;
c = getchar();
}
return f * fu;
}
const int N = 1e5 + 10;
vi seq;
int a[N], b[N], cnt[N << 1], n, T;
mii num;
queue<int> q;
set<int> st[N << 1];
int main() {
T = qr();
int cse = 0;
while (T--) {
n = qr();
seq.clear(), num.clear();
repi(i, 1, 2 * n)st[i].clear(), cnt[i] = 0;
while (!q.empty())q.pop();
repi(i, 1, n)a[i] = qr(), b[i] = qr(), seq.pb(a[i]), seq.pb(b[i]);
sort(all(seq));
seq.erase(unique(all(seq)), seq.end());
int tot = seq.size(), ans = 0;
repi(i, 0, tot - 1)num[seq[i]] = i + 1;
repi(i, 1, n) {
a[i] = num[a[i]], cnt[a[i]]++, st[a[i]].insert(i);
b[i] = num[b[i]], cnt[b[i]]++, st[b[i]].insert(i);
}
repi(i, 1, tot)if (cnt[i] == 1)q.push(i);
while (!q.empty()) {
int x = q.front();
q.pop();
if (!cnt[x])continue;
int pos = *st[x].begin();
ans++, st[a[pos]].erase(pos), st[b[pos]].erase(pos);
if (!--cnt[a[pos]])tot--;
if (!--cnt[b[pos]])tot--;
if (cnt[a[pos]] == 1)q.push(a[pos]);
if (cnt[b[pos]] == 1)q.push(b[pos]);
}
printf("Case #%d: %d\n", ++cse, ans + tot);
}
return 0;
}