Educational Codeforces Round 49 (Rated for Div. 2) F. Session in BSU

F. Session in BSU
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Polycarp studies in Berland State University. Soon he will have to take his exam. He has to pass exactly
n
exams.

For the each exam
i
there are known two days:
a
i
— day of the first opportunity to pass the exam,
b
i
— day of the second opportunity to pass the exam (
a
i
<
b
i
). Polycarp can pass at most one exam during each day. For each exam Polycarp chooses by himself which day he will pass this exam. He has to pass all the
n
exams.

Polycarp wants to pass all the exams as soon as possible. Print the minimum index of day by which Polycarp can pass all the
n
exams, or print -1 if he cannot pass all the exams at all.

Input
The first line of the input contains one integer
n
(
1

n

10
6
) — the number of exams.

The next
n
lines contain two integers each:
a
i
and
b
i
(
1

a
i
<
b
i

10
9
), where
a
i
is the number of day of the first passing the
i
-th exam and
b
i
is the number of day of the second passing the
i
-th exam.

Output
If Polycarp cannot pass all the
n
exams, print -1. Otherwise print the minimum index of day by which Polycarp can do that.

Examples
inputCopy
2
1 5
1 7
outputCopy
5
inputCopy
3
5 13
1 5
1 7
outputCopy
7
inputCopy
3
10 40
40 80
10 80
outputCopy
80
inputCopy
3
99 100
99 100
99 100
outputCopy
-1
题意:有n个测试,每个测试可以有两个考试时间可以选择,如果想尽快把所有考试考完,问最少需要的时间;
做法:因为每个测试只有两个选择,那么可以把测试和时间连接起来,然后会的的一些连通图,设联通图里面为测试的点为a类点,为考试时间的点为b类点,那么在一个连通图里面b类点的个数小于等于a类点个数+1,因为最开始只有一个a类点,两个b类点,加入有一个a类点被连接进来,那么它所连接的两个点,最多只有一个点没有在当前的连通图里。
可知连通图里没有环,每个a类点旁边必定是b类点,如果b类点比a类点多一个,那么可以把这个图里面最大的那个b类点抠出来,剩下的点必定可以得到a类点和b类点的匹配。
如果b类点的个数等于a类点,那么必定是所有点相连。
如果b类点的个数小于a类点,明显是无解的。

#include
using namespace std;
const int N = 1e6+100;
int a[N],b[N];
map mp;
int fa[N*3];
int Find(int x){return x==fa[x]?x:fa[x] = Find(fa[x]); }
int cnt[N];
int mx[N],mx2[N];
int num[N*3];
int main(){
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++) scanf("%d %d",&a[i],&b[i]);
    for(int i = 1;i <= n;i ++){
        mp[a[i]] = 1;
        mp[b[i]] = 1;
    }
    int tot = 0;
    for(auto &iter: mp){
        tot++;
        num[n+tot] = iter.first;
        iter.second = n+tot;

    }
    for(int i = 1;i <= n+tot;i ++) fa[i] =i;
    for(int i = 1;i <= n;i ++){
        int f1 = Find(i);
        int f2 = Find(mp[a[i]]);
        if(f1 != f2){
            fa[f2] = f1;
        }
        int f3 = Find(mp[b[i]]);
        if(f1 != f3){
            fa[f3] = f1;
        }
    }
    memset(mx,-1,sizeof(mx));
    memset(mx2,-1,sizeof(mx2));
    for(int i = 1;i <= n+tot;i ++){

        int ff = Find(i);
        //if(i > n){cout <<"!!!" << i << ' '<< num[i] << ' ' < mx[ff]){
                mx2[ff] = mx[ff];
                mx[ff] = num[i];
            }
            else if(mx2[ff] == -1 || num[i] > mx2[ff]){
                mx2[ff] = num[i];
            }
        }
    }
    bool ans = true;
    int ret = 0;
    for(int i = 1;i <= n;i ++){
        //cout << i << ' '<< fa[i] << ' '<< cnt[i] << ' '<< mx[i]<< ' '< 0) ans = false;
            if(cnt[i] == 0){
                ret = max(ret,mx[i]);
            }
            if(cnt[i] < 0){
                ret = max(ret,mx2[i]);
            }
        }
    }
    if(ans){
        printf("%d\n",ret);
    }
    else puts("-1");

    return 0;
}

你可能感兴趣的:(算法理解)