题意:
n个学生要组成一个小组参加会议(可以不参加),
1.对于每两个朋友(x ,y),如果他们俩都参加会议,该小组的友好价值将会增加 1;如果其中只有一位参加会议,则该组的友好价值将降低 1。
3.如果n个学生参加会议,对团队的友好价值将降低n.
题目:
Professor Alex will organize students to attend an academic conference.
Alex has n excellent students, and he decides to select some of them (possibly none) to attend the conference. They form a group. Some pairs of them are friends.
The friendly value of the group is initially 0. For each couple of friends (x,y), if both of them attend the conference, the friendly value of the group will increase 1, and if only one of them attends the conference, the friendly value of the group will decrease 1. If k students attend the conference, the friendly value of the group will decrease k.
Alex wants to make the group more friendly. Please output the maximum friendly value of the group.
Input
The first line of the input gives the number of test cases, T (1≤T≤104). T test cases follow.
For each test case, the first line contains two integers n (1≤n≤3×105) and m (1≤m≤106), where n is the number of students and m is the number of couples of friends.
Each of the following m lines contains two integers xi,yi (1≤xi,yi≤n,xi≠yi), representing student xi and student yi are friends. It guaranteed that unordered pairs (xi,yi) are distinct.
The sum of n in all test cases doesn’t exceed 106, and the sum of m in all test cases doesn’t exceed 2×106.
Output
For each test case, output one line containing “Case #x: y”, where x is the test case number (starting from 1), and y is the maximum friendly value of the group.
Example
Input
2
4 5
1 2
1 3
1 4
2 3
3 4
2 1
1 2
Output
Case #1: 1
Case #2: 0
分析:
1.由题意,友好价值=组群里的边数-点数;
2.那么怎么求最大友好价值?由于对于每两个朋友(x ,y),如果他们俩都参加会议,该小组的友好价值将会增加 1;如果其中只有一位参加会议,则该组的友好价值将降低 1,所以我们用并查集,直接找根节点遍历到最后,这时就变成了一个个的组群,我们只要判断这些组群是否参加会议即可,当组群里的边数-点数<0时,不让其参加,反之参加即可求得。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int M=3e5+10;
int t,n,m,k,ans;
int f[M],a[M],b[M];
int getf(int x){if(f[x]==x) return x;return f[x]=getf(f[x]);
}
int main(){cin>>t;k=0;while(t--){cin>>n>>m;for(int i=1;i<=n;i++){f[i]=i;a[i]=0;//记录边,起始边个数为零。b[i]=1;//记录点,原始本身就为一个点。}for(int i=1;i<=m;i++){int t1,t2;scanf("%d%d",&t1,&t2);int u=getf(t1);int v=getf(t2);if(u==v) a[u]++;else {f[v]=u;a[u]+=a[v]+1;//因为最终怕判断的根节点判组群,所以记录边和点只需要在根节点上即可。b[u]+=b[v];}}ans=0;for(int i=1;i<=n;i++){if(i==f[i]&&a[i]-b[i]>0)ans+=a[i]-b[i];}printf("Case #%d: %d\n",++k,ans);}return 0;
}