题意: 给出一个N个点,M条边的无向图(无自环,重边),现在构造出一个新图,有N*N个点,若在原图中存在边(a,b)和(a’,b’),则新图中存在从点(a,a’)到点(b,b’)的无向边。求新图中的联通分量的个数
分析:
我们可以将原题转换成:给出2个无向图A和B,当且仅当图A中存在边(a,b),图B中存在边(a’,b’)时,新图中存在点(a,a’)到点(b,b’)的无向边。
所以,我们可以发现,新图中2个点连接的前提条件下,是这2个点对应的(x,y)坐标在原图中都对应连接。
那么,我们可以开始计算原图中孤立点的个数:A图中孤立的点和B图中孤立的点构成新图中的点 (Ia,Ib) 也是孤立的
A图中孤立的点和B图中非孤立的点构成新图中的点 (Ia,Nb−Ib) 也是孤立的
B图中孤立的点和A图中非孤立的点构成新图中的点 (Ib,Na−Ia) 也是孤立的
处理完孤立的点后,我们再来看剩下的联通分量。每一个联通分量我们可以当做一个‘点’来处理,这样看,似乎它的计算方式和孤立点一样: Pa×Pb 即可。但是如果这个联通分量是二分图的话,根据二分图的性质,情况就不一样了:
假设原图A和B中都含有一个二分图,且每个二分图分成S集合和T集合,那么以这两个二分图为基础,我们可以在新图中构建出2个联通分量: (SA,SB)−(TA,TB) 和 (SA,TB)−(TA,SA)
所以我们需要单独计算出二分图联通分量的个数 Q 和非二分图联通分量的个数
P 那么这些原图中联通分量构成新图中联通分量的为: (PA,PB) , (PA,QB) , (PB,QA) 和 2∗(QA,QB)
所以最终结果为 :
(IA×IB+IA×(NB−IB)+IB×(NA−IA))+PA×PB+PA×QB+QA×PB+2×QA×QB
并且算法复杂度为二分图判定的时间复杂度,即等同于遍历了所有边,即 O(M)AC 代码:
/*************************************************************************
> File Name: test.cpp
> Author: Akira
> Mail: qaq.febr2.qaq@gmail.com
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<cstring>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;
#define MaxN 100010
#define MaxM MaxN*20
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
const int mod = 1E9 + 7;
const double eps = 1e-6;
#define bug cout<<88888888<<endl;
#define debug(x) cout << #x" = " << x;
int N, M;
struct Edge
{
int u, v, next;
}edge[MaxM];
int cont;
int head[MaxN];
int vis[MaxN];
int col[MaxN];
void add(int u, int v)
{
edge[cont].u = u;
edge[cont].v = v;
edge[cont].next = head[u];
head[u] = cont++;
}
void Add(int u, int v) { add(u, v); add(v, u); }
void init()
{
cont = 0;
MST(head, -1);
CLR(vis);
}
int main()
{
//std::ios::sync_with_stdio(false);
while (~scanf("%d%d", &N, &M))
{
init();
while (M--)
{
int u, v;
scanf("%d%d", &u, &v);
Add(u, v);
}
LL I = 0, Q = 0, P = 0;
for (int i = 1; i<=N; i++)
{
if(!vis[i])
{
bool flag = true;
queue<int> q;
vector<int> V;
q.push(i);
V.push_back(i);
vis[i] = 1;
col[i] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v = edge[j].v;
if(!vis[v])
{
vis[v] = 1;
q.push(v);
V.push_back(v);
col[v] = col[u] + 1;
}
else
{
if( (col[v]-col[u])%2 == 0) flag = false;
}
}
}
if (V.size() == 1) I++;
else
{
if (flag) Q++;
else P++;
}
}
}
//cout << I << " " << Q << " " << P << endl;
LL ans = 2*I*N - I*I + P*P + 2 * P*Q + 2*Q*Q;
printf("%lld\n", ans);
}
//system("pause");
}