Description
从前有个包含n个点,m条边,无自环和重边的无向图。
对于两个没有直接连边的点u;v,你可以将它们合并。具体来说,你可以删除u;v及所有以它们作为端点的边,然后加入一个新点x,将它与所有在原图中与u或v有直接连边的点连边。
你需要判断是否能通过若干次合并操作使得原图成为一条链,如果能,你还需要求出这条链的最大长度
题解
先判断无解的情况,
很显然一个三元环是无解的,
推广一下,只要有奇环就是无解。
考虑构造一种合法解,
枚举一个点作为链的顶端,
那么可以将所有到它距离相同的点缩成一个点。
这样最后出来的,一定是一条链,
如何是链最长,那显然是图的直径了。
对于不同的联通块,就将他们的答案加在一起。
code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
int n,m,nxt[N*2],lst[N],to[N*2],tot,x,y;
int ans,mx[N],cnt,col[N],dis[N],w[N];
int head,tail,q[N];
bool bz[N];
void ins(int x,int y)
{
nxt[++tot]=lst[x];
to[tot]=y;
lst[x]=tot;
}
void dfs(int x,int fa,int dep)
{
col[x]=cnt;w[x]=dep;
for(int i=lst[x];i;i=nxt[i])
{
if(to[i]==fa)continue;
if(!col[to[i]])dfs(to[i],x,dep^1);else
if(w[x]==w[to[i]])ans=-1;
}
}
void work(int st)
{
memset(dis,128,sizeof(dis));
memset(bz,1,sizeof(bz));
for(dis[st]=head=bz[q[tail=1]=st]=0;head<tail;)
{
x=q[++head];
for(int i=lst[x];i;i=nxt[i])
if(dis[to[i]]<dis[x]+1 && bz[to[i]])
{
dis[to[i]]=dis[x]+1;
bz[q[++tail]=to[i]]=0;
}
}
}
int main()
{
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
read(n);read(m);
for(int i=1;i<=m;i++)
read(x),read(y),ins(x,y),ins(y,x);
for(int i=1;i<=n;i++)
if(!col[i])cnt++,dfs(i,0,0);
if(ans==-1)
{
printf("%d",ans);
return 0;
}
for(int i=1;i<=n;i++)
{
work(i);
for(int i=1;i<=n;i++)
mx[col[i]]=max(mx[col[i]],dis[i]);
}
for(int i=1;i<=cnt;i++)
ans=ans+mx[i];
printf("%d\n",ans);
return 0;
}