题意
题解
这题一开始感觉无从下手,所以我们要尝试得到一些结论。
自己画一画可以发现,一定是两两互为对方的庇护所。这样才有可能保证任意两个不同的城市庇护所不同。否则由于原图没有环,到后面必定会撞上。
树上的完美匹配要么无解,要么就只有唯一解。直接
dfs
一趟就能得到匹配关系了。
庇护所都确定了就很简单了,就剩下一些危险度大小关系的限制。直接根据限制建拓扑图,然后用堆搞一搞就能满足字典序最小了,很经典的方法。
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000005,maxe=2000005;
int n,m,pr[maxn],d[maxn];
int fir[maxn],son[maxe],nxt[maxe],tot;
priority_queue < int,vector<int>,greater<int> > _heap;
vector< pair<int,int> > tem;
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int dfs(int x,int pre){ //0完全匹配 1剩下根 2爆炸
int cnt=0;
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre){
int t=dfs(son[j],x); if(t==2) return 2;
if(t==1) cnt++, pr[x]=son[j], pr[son[j]]=x;
}
if(cnt>1) return 2;
if(!cnt) return 1;
return 0;
}
int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
if(dfs(1,1)){ printf("-1\n"); return 0; }
for(int i=1;i<=n;i++)
for(int j=fir[i];j;j=nxt[j])
if(son[j]!=pr[i]) tem.push_back(make_pair(pr[i],son[j]));
memset(fir,0,sizeof(fir)); tot=0;
for(int i=0;i<tem.size();i++) add(tem[i].first,tem[i].second), d[tem[i].second]++;
for(int i=1;i<=n;i++) if(!d[i]) _heap.push(i);
while(!_heap.empty()){
int x=_heap.top(); _heap.pop();
printf("%d ",x);
for(int j=fir[x];j;j=nxt[j]) if(!(--d[son[j]])) _heap.push(son[j]);
}
return 0;
}