正题
大概想了一个晚上吧,首先可以发现就是将一个独立集不断合并起来之后,成为一个链的形状,相当于有边的只有相邻的两个独立集。
考虑枚举链的一个端点,容易发现存在一种最优方案满足这个端点的独立集只有一个点,否则可以将同一个独立集的其他点放到链上第三个独立集,不影响后面的顺序而且只会使答案变得更大。
枚举完这个点之后,考虑当前层的点的连接点有没有被加入到独立集,如果没有,那么就加入到下一层,否则,如果和当前点在同一层(也就是有奇数环),那么无解,否则就不用理(肯定会在当前点的上一层或者下一层),肯定合法。
这个过程是
O
(
n
(
n
+
m
)
)
O(n(n+m))
O(n(n+m))的。
考虑先判断是否有奇环,后面再使用bitset优化图的遍历就可以了,时间复杂度
O
(
m
+
n
3
64
)
O(m+\frac{n^3}{64})
O(m+64n3)
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int first[N],len,n,m;
int op[N],qs[N];
bool tag[N],vis[N];
vector<int> V;
bitset<1001> s[1001],f,g,S;
bool dfs(int x,bool c){
vis[x]=true;tag[x]=c;V.push_back(x);S[x]=true;
bool tf=true;
int now=s[x]._Find_next(0);
while(now<=n){
if(!vis[now]) tf&=dfs(now,c^1);
else if(tag[x]==tag[now]) return false;
now=s[x]._Find_next(now);
}
return tf;
}
int gs(int x){
g.reset();g[x]=true;
vector<int> P;
int ans=-1;
while(1){
if(g.count()==0) break;
ans++;P.resize(0);
int now=g._Find_next(0);
while(now<=n) P.push_back(now),now=g._Find_next(now);
g.reset();for(int i=0;i<P.size();i++) g|=s[P[i]],f[P[i]]=0;g&=f;
}
return ans;
}
int solve(int x){
V.resize(0);S.reset();
if(!dfs(x,0)) return -1;
int mmax=0;
for(int i=0;i<V.size();i++) f=S,mmax=max(mmax,gs(V[i]));
return mmax;
}
int main(){
scanf("%d %d",&n,&m);
int x,y;
for(int i=1;i<=m;i++) scanf("%d %d",&x,&y),s[x][y]=s[y][x]=true;
int ans=0;
for(int i=1;i<=n;i++) if(!vis[i]){
int tmp=solve(i);
if(tmp==-1) {printf("-1");return 0;}
ans+=tmp;
}
printf("%d",ans);
}