Welcome Party ZOJ - 4109 (思维+并查集)
题目链接:
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 }