题目链接:
Welcome Party
题目大意:给你T组测试样例,然后n个人,m个关系,每一个关系包括两个人,这两个人为好朋友,然后问你怎么安排顺序,使得整个队伍的友情损失度最小(当一个人放置时,如果他的前面中没有他的朋友,那么整个队伍的朋友损失度就会加1)
具体思路:首先用并查集求出每一个联通块,然后用一个超级汇点连向这些连通块的根,然后优先队列+bfs求出字典序最小的正解就可以了。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define inf 0x3f3f3f3f 4 # define ll long long 5 const int maxn = 2e6+100; 6 int father[maxn]; 7 vector<int>Edge[maxn]; 8 vector<int>sto; 9 int vis[maxn]; 10 int Find(int t) 11 { 12 return t==father[t]?t:father[t]=Find(father[t]); 13 } 14 void mege(int st,int ed) 15 { 16 int t1=Find(st); 17 int t2=Find(ed); 18 if(t1==t2)return ; 19 if(t1>t2)swap(t1,t2); 20 father[t2]=t1; 21 } 22 void bfs(int root) 23 { 24 priority_queue<int,vector<int>,greater<int> >q; 25 while(!q.empty())q.pop(); 26 q.push(root); 27 vis[root]=1; 28 while(!q.empty()) 29 { 30 int top=q.top(); 31 q.pop(); 32 // if(top!=0) 33 sto.push_back(top); 34 for(int i=0; i<Edge[top].size(); i++) 35 { 36 int to=Edge[top][i]; 37 if(vis[to]) 38 continue; 39 vis[to]=1; 40 q.push(to); 41 } 42 } 43 } 44 int main() 45 { 46 int T; 47 scanf("%d",&T); 48 while(T--) 49 { 50 int n,m,st,ed; 51 scanf("%d %d",&n,&m); 52 sto.clear(); 53 for(int i=0; i<=n; i++)//注意从0开始清空 54 { 55 father[i]=i; 56 Edge[i].clear(); 57 vis[i]=0; 58 } 59 for(int i=1; i<=m; i++) 60 { 61 scanf("%d %d",&st,&ed); 62 Edge[st].push_back(ed); 63 Edge[ed].push_back(st); 64 mege(st,ed); 65 } 66 int ans=0; 67 for(int i=1; i<=n; i++) 68 { 69 if(Find(i)!=i) 70 continue; 71 Edge[0].push_back(i); 72 ans++; 73 } 74 bfs(0); 75 printf("%d\n",ans); 76 for(int i=1; i<sto.size(); i++) 77 { 78 if(i==1) 79 printf("%d",sto[i]); 80 else 81 printf(" %d",sto[i]); 82 } 83 printf("\n"); 84 } 85 return 0; 86 }
原文地址:https://www.cnblogs.com/letlifestop/p/10804321.html
时间: 2024-12-09 00:03:12