题意:
给出n场考试,每场考试有2天可以通过(第aiai与bibi天)。每天最多参加一场考试,现在要求所有考试全部通过的最小天数。
分析:
可以把每天看作一个点,每次考试看作一条边。现在要每条边选择一个点,把每个联通块分别考虑,很容易发现:
如果是树(n=m+1),那么只有1个点不用选,为了最优性,肯定不选最大的一个。
如果是基环外向树(n=m),那么所有点都必须选。
如果n<mn<m,则无法满足。
所以只需要维护每个联通块的最大值,次大值即可,顺便判断一下这个联通块是否刚好只有1个环。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 2000010
#define MOD 998244353
using namespace std;
typedef long long ll;
int n,u,v;
int val[MAXN];
pair<int,int> l[MAXN];
int fa[MAXN];
bool spe[MAXN];
int maxv[MAXN],secv[MAXN];
int c[5];
int get_fa(int x){
if(fa[x]==0)
return x;
fa[x]=get_fa(fa[x]);
return fa[x];
}
bool merge(int u,int v){
u=get_fa(u);
v=get_fa(v);
if(u==v){
if(spe[u]==1)
return 0;
spe[u]=1;
}
else{
fa[u]=v;
spe[v]=max(spe[v],spe[u]);
c[0]=maxv[v];
c[1]=maxv[u];
c[2]=secv[v];
c[3]=secv[u];
sort(c,c+4);
maxv[v]=c[3];
secv[v]=c[2];
}
return 1;
}
int main(){
SF("%d",&n);
for(int i=1;i<=n;i++){
SF("%d%d",&u,&v);
l[i]=make_pair(u,v);
val[i*2]=u;
val[i*2-1]=v;
}
sort(val+1,val+1+2*n);
int cnt=unique(val+1,val+1+2*n)-val-1;
for(int i=1;i<=n;i++){
l[i].first=lower_bound(val+1,val+1+cnt,l[i].first)-val;
l[i].second=lower_bound(val+1,val+1+cnt,l[i].second)-val;
//PF("{%d %d}",l[i].first,l[i].second);
}
for(int i=1;i<=cnt;i++){
maxv[i]=val[i];
secv[i]=0;
}
for(int i=1;i<=n;i++){
if(merge(l[i].first,l[i].second)==0){
PF("-1");
return 0;
}
}
int ans=0;
for(int i=1;i<=cnt;i++)
if(i==get_fa(i)){
if(spe[i]==1)
ans=max(ans,maxv[i]);
else
ans=max(ans,secv[i]);
}
PF("%d",ans);
}
本文探讨了一种算法问题,即如何安排最少的天数来完成一系列考试,每场考试可以在两个指定的日子之一进行。文章提供了详细的算法分析,包括如何构建图论模型,并通过联通块分析得出最优解的方法。
357

被折叠的 条评论
为什么被折叠?



