Hongcow Builds A Nation CodeForces

来源:互联网 发布:java鱼雷2017款评测 编辑:程序博客网 时间:2024/06/05 06:28

Problem Description、

Hongcow is ruler of the world. As ruler of the world, he wants to make it easier for people to travel by road within their own countries.

The world can be modeled as an undirected graph with n nodes and m edges. k of the nodes are home to the governments of the k countries that make up the world.

There is at most one edge connecting any two nodes and no edge connects a node to itself. Furthermore, for any two nodes corresponding to governments, there is no path between those two nodes. Any graph that satisfies all of these conditions is stable.

Hongcow wants to add as many edges as possible to the graph while keeping it stable. Determine the maximum number of edges Hongcow can add.

Input
The first line of input will contain three integers n, m and k (1 ≤ n ≤ 1 000, 0 ≤ m ≤ 100 000, 1 ≤ k ≤ n) — the number of vertices and edges in the graph, and the number of vertices that are homes of the government.

The next line of input will contain k integers c1, c2, …, ck (1 ≤ ci ≤ n). These integers will be pairwise distinct and denote the nodes that are home to the governments in this world.

The following m lines of input will contain two integers ui and vi (1 ≤ ui, vi ≤ n). This denotes an undirected edge between nodes ui and vi.

It is guaranteed that the graph described by the input is stable.

Output
Output a single integer, the maximum number of edges Hongcow can add to the graph while keeping it stable.

Examples

input
4 1 2
1 3
1 2
output
2

input
3 3 1
2
1 2
1 3
2 3
output
0

Note
For the first sample test, the graph looks like this:
这里写图片描述
Vertices 1 and 3 are special. The optimal solution is to connect vertex 4 to vertices 1 and 2. This adds a total of 2 edges. We cannot add any more edges, since vertices 1 and 3 cannot have any path between them.
For the second sample test, the graph looks like this:
这里写图片描述
We cannot add any more edges to this graph. Note that we are not allowed to add self-loops, and the graph must be simple.

大致题意:给你一个无向图,有n个点,m条边,有k个重要点,任意两个重要点不能连通,否则图不稳定。初始图一定的稳定的,问我们最多还能添加多少边,使得图依旧是稳定的。

思路:首先我们用并查集将现在所有的连通块找出来,并且给存在重要点的连通块标记一下。对于一个点数为x的连通块我们最多可以有x*(x-1)/2 条边。对于没有重要点存在的连通块,我们可以先将他们全部连起来,假设得到点数为cnt,然后我们还可以选择一个有重要点的连通块与之相连,为了得到最多的边,所以我们选择一个点数最多的有重要点的连通块连接(假设该部分点数为maxn)。然后我们将剩下的其他包含重要点的连通块边数添加至temp*(temp-1)/2.
那么最多边数ans=(cnt+maxn)* (cnt+maxn-1)/2+其他各个重要点连通块的边数Σ temp*(temp-1)/2.
最后减去原有的边数m ,ans-m即是所能添加的最多边数。

代码如下

#include<iostream>#include<algorithm>#include<string>#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<cstring>using namespace std;const int Maxn=1005;int n,m,k;int pre[Maxn];int flag[Maxn];//记录连通块是否有重要点int sum[Maxn];//记录连通块的点的数量int find(int x){   int r=x;   while (pre[r]!=r)   r=pre[r];   int i=x; int j;   while(i!=r)   {       j=pre[i];       pre[i]=r;       i=j;   }   return r;}void join(int x,int y){    int fx=find(x);    int fy=find(y);    if(fx!=fy)    {        pre[fy]=fx;//将fy的父节点记为fx        sum[fx]+=sum[fy];//更新父节点为fx的连通块的点的个数        flag[fx]+=flag[fy];//更新父节点为fx的连通块的重要点的个数    }}int main(){    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        memset(flag,0,sizeof(flag));        memset(sum,0,sizeof(sum));        for(int i=1;i<=n;i++)        {            pre[i]=i;            sum[i]=1;        }        for(int i=1;i<=k;i++)        {            int x;            scanf("%d",&x);            flag[x]=1;//标记为重要点        }        for(int i=1;i<=m;i++)        {            int x,y;            scanf("%d%d",&x,&y);            join(x,y);        }        int output=0;        int maxn=0;        for(int i=1;i<=n;i++)        {            if(pre[i]==i&&flag[i]==1)//如果该连通块有重要点            {                maxn=max(maxn,sum[i]);            }        }        int cnt=0;        int tmp=0;        for(int i=1;i<=n;i++)        {            if(pre[i]==i)//找到一个连通块            {            if(flag[i]==1)//如果该连通块有重要点            {                if(sum[i]==maxn)//如果点数是最大点数maxn                {                    if(tmp==0)                    {                        tmp=1;                    }                    else                     {                        output+=sum[i]*(sum[i]-1)/2;//如果有多个点数为maxn,只能选择一个与cnt连,剩下的只能自己连                    }                }                else                 {                    output+=sum[i]*(sum[i]-1)/2;//自己连                }            }            else             {                cnt+=sum[i];            }         }        }        output+=(cnt+maxn)*(cnt+maxn-1)/2;        printf("%d\n",output-m);    }   return 0;}
0 0