分析:
比较复杂的一道思维题。。。
先考虑树的情况,把所有点按照深度的奇偶性分为两类,在所有深度为奇的点放一个“+1”,在所有深度为偶的点放一个“-1”。这样一来,每次染色,就可以看作交换了一对相邻的“+1”和“-1”。目标状态就是所有的“+1”移动到“-1”所在的位置,所有的“-1”移动到“+1”所在的位置(即染色次数为奇数)。
然后所有"+1"和“-1”两两配对一定是最优的,并且,把配对的两个交换的代价即为其路径长度。
这样就可以解决树的情况了。
奇环:
随便找到环上的一条边(u,v),很显然,所有点到达u的路径长度奇偶性与到达v的路径长度奇偶性是相同的。也就是说,任意一个u匹配的点,都能匹配v,反之亦然。所以仍然按照上面的方法,只不过这两个点的"1"和“-1”的个数有无限个,不过必须相同。
因为如果有两个相同的交换,可以改为:在u换走一个,在v换走一个,然后此时u,v颜色相同,选中u,v使得它们恢复原状。所以可以无限地恢复,所以这两个点的“1”和“-1”有无限个。
然后可以先算出这条边的贡献,再套用树的方法。
偶环:
任意找到一条边(u,v),可以考虑在最优条件下,这条边的贡献,然后删去这条边就能照样做了。这里我觉得某队爷的题解写得很清楚了:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
typedef long long ll;
int n,m;
struct node{
int x;
node *nxt;
}edge[MAXN*2];
node *head[MAXN],*ncnt=edge;
void add_edge(int u,int v){
++ncnt;
ncnt->x=v;
ncnt->nxt=head[u];
head[u]=ncnt;
}
int dep[MAXN],ods[MAXN],cirlen,sum[MAXN],tot,cu,cv;
bool vis[MAXN];
ll ans;
void dfs(int x,int f){
vis[x]=1;
dep[x]=dep[f]^1;
if(dep[x]==0)
sum[x]=1;
else
sum[x]=-1;
tot+=sum[x];
for(node *v=head[x];v!=NULL;v=v->nxt){
int u=v->x;
if(u==f)
continue;
if(vis[u]==1){
cirlen=dep[u]^dep[x]^1;
cu=x;
cv=u;
continue;
}
dfs(u,x);
}
}
void solve(int x,int f){
vis[x]=1;
for(node *v=head[x];v!=NULL;v=v->nxt){
int u=v->x;
if(u==f||vis[u]==1)
continue;
solve(u,x);
ods[x]+=ods[u];
sum[x]+=sum[u];
}
}
int A[MAXN],cnt;
int main(){
SF("%d%d",&n,&m);
int u,v;
for(int i=1;i<=m;i++){
SF("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0);
if(n==m+1){
if(tot!=0){
PF("-1");
return 0;
}
}
else{
if(cirlen==1){
if(tot%2!=0){
PF("-1");
return 0;
}
sum[cu]-=tot/2;
sum[cv]-=tot/2;
ans+=abs(tot/2);
}
else{
if(tot!=0){
PF("-1");
return 0;
}
ods[cu]=1;
ods[cv]=-1;
}
}
memset(vis,0,sizeof vis);
solve(1,0);
for(int i=1;i<=n;i++){
if(ods[i]==0)
ans+=abs(sum[i]);
else{
if(ods[i]==1)
sum[i]=-sum[i];
A[++cnt]=sum[i];
}
}
if(cirlen==0&&cu!=0){
A[++cnt]=0;//LCA of cu and cv
sort(A+1,A+1+cnt);
ll mid=A[(cnt+1)/2];
for(int i=1;i<=cnt;i++)
ans+=abs(A[i]-mid);
}
PF("%lld",ans);
}