题解
答案一定可以为一条链,因为对于答案树中的每个节点将其子节点从大到小排序放入链尾后依旧成立。
探讨限制条件:(1)(b)只能为(n),因为(n)一定是它所在连通分量中的最大值。(2)设(cnt_i)表示(i)作为(a)出现的次数,则(sumlimits_{j=1}^icnt_j<i),因为每一个(cnt)都代表需要生成一个新的节点,而与(i)在同一个连通分量中的点一定(le i),所以当(le i)的点不够(cnt)时一定无法实现。
具体构造:从小到大枚举(a_i)加入链中,对于多组同样的(a,b),它们之间的点(j)一定(le a,b),枚举(j)即可。时间复杂度为(O(n^2))。
AC题解
#include<bits/stdc++.h>
using namespace std;
const int N=1010,inf=0x3f3f3f3f;
int cnt[N];
bool vis[N];//i是否在已链中
int main()
{
int n,a,b,sum=0;
scanf("%d",&n);
//限制条件(1)
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
if(b!=n) {printf("NO"); return 0;}
cnt[a]++; vis[a]=1;
}
//限制条件(2)
for(int i=1;i<n;i++)
{
sum+=cnt[i];
if(sum>i) {printf("NO"); return 0;}
}
int lst=-1,nxt;//lst:当前链尾,nxt:当前元素
printf("YES
");
for(int i=1;i<n;i++)
{
if(!vis[i]) continue;
if(cnt[i]>0)
{
if(lst!=-1) printf("%d %d
",lst,i);
lst=i; cnt[i]--;
}
while(cnt[i]>0)//多组同样的a,b时
{
for(int j=1;j<i;j++)
if(!vis[j]) {nxt=j; break;}
printf("%d %d
",lst,nxt);
vis[nxt]=1;
lst=nxt; cnt[i]--;
}
}
printf("%d %d
",lst,n);
return 0;
}