首先我们把日期看成点,每个考试都连接了两个点,而合法的情况就是每条边都至少有一个点和他配对,和二分图匹配很像。。
但是时间明显不够,那么我们可以转换思路,通过连边,原图变为了一些连通块,而对于每个连通块,就有以下几种情况
1.这个连通块是个树,那么每条边都有点,还多出一个点,所以最后要找的就是次大的点。
2.这个连通块是一个基环树(就是只有一个环的树),那么每个点正好对应一条边,要用的就是最大的点。
3.这个连通块的边数>点数,那么一定不合法,输出-1即可。
PS:对于2和3情况的判定我换了好几种方法终于对了。。。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
map<int,int>M,N;
int cnt,n,used[2000006],hh[2000006];
vector<int>W[2000006];
int maxx,flag,cimax,ans;
struct dd
{
int u,v;
}ddd[1000006];
void dfs(int u,int fa)
{
used[u]++;
if(u<maxx)cimax=max(cimax,u);
else if(u>maxx) cimax=maxx,maxx=u;
int l=W[u].size()-1;
for(int i=0;i<=l;i++)
{
if(W[u][i]==fa)continue;
if(used[W[u][i]])
{
used[W[u][i]]++;
if(used[W[u][i]]==2)
{
flag++;
if(flag>2)//有多组环不合法
{
printf("-1");
exit(0);
}
}
if(used[W[u][i]]>2)//一个点被超过2条边连不合法
{
printf("-1");
exit(0);
}
continue;
}
dfs(W[u][i],u);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ddd[i].u,&ddd[i].v);
hh[++cnt]=ddd[i].u,hh[++cnt]=ddd[i].v;
}
sort(hh+1,hh+1+cnt);int tr=0;
for(int i=1;i<=cnt;i++)
{
if(!M[hh[i]])M[hh[i]]=++tr,N[tr]=hh[i];
}
for(int i=1;i<=n;i++)
{
W[M[ddd[i].u]].push_back(M[ddd[i].v]);
W[M[ddd[i].v]].push_back(M[ddd[i].u]);
}
for(int i=1;i<=tr;i++)
{
maxx=0,cimax=0,flag=0;
if(!used[i])
{
dfs(i,i);
if(flag)
{
ans=max(ans,maxx);
}else
{
ans=max(ans,cimax);
}
}
}
printf("%d",N[ans]);
return 0;
}