为了校赛 特地去学图论,刚搞到双联通分量,就弄这么一道神题出来,,,
据小优说她同学搞了4个月,她搞了2天。。。
嘛,我是看了人家的题解,拿着别人的模版,搞了一下午= = 。。。其实自己的东西用到的很少啊。。。
首先把原图搞成补图,注意补图中不要有自环= =。。
把所有双联通分量搞出来,对于每一个双联通分量判断是否是二分图,
不是的话,把双联通分量里面的点标记上就好了。。。
最后计算未标记的点的个数=n-标记的个数。。。
代码
#include<cstdio> #include<vector> #define X 1010 using namespace std; bool map[X][X]; vector<int>edge[X]; vector<vector<int> >connect; int dfn[X],low[X],in_seq[X]; int stack[X],list[X],as[X]; int cnt,top,pop,len; void biconnect(int v){ stack[++top]=v; dfn[v]=low[v]=pop++; int i,succ; for(i=edge[v].size()-1;i>=0;i--){ succ=edge[v][i]; if(dfn[succ]==-1){ biconnect(succ); if(low[succ]>=dfn[v]){ cnt++;len=0; do{ in_seq[stack[top]]=cnt; list[len++]=stack[top]; top--; }while(stack[top+1]!=succ); in_seq[v]=cnt; list[len++]=v; vector<int> tmp(list,list+len); connect.push_back(tmp); } low[v]=min(low[v],low[succ]); } else low[v]=min(low[v],dfn[succ]); } } bool flag,bif[X]; int vis[X]; void dfs(int u,int e){ int v,i,n=edge[u].size(); vis[u]=e+1; for(i=0;i<n&&flag;i++){ v=edge[u][i]; if(bif[v]){ if(vis[v]==vis[u]) flag=0; if(!vis[v])dfs(v,!e); } } } void make(vector<int> v){ int i,j,n; n=v.size();flag=1; if(n<3)return ; for(i=0;i<n;i++) bif[v[i]]=1; dfs(v[0],0); if(!flag)for(i=0;i<n;i++)as[v[i]]=1; } int main(){ int i,j,n,m,u,v; while(scanf("%d%d",&n,&m),n||m){ for(i=1;i<=n;i++) for(j=1;j<=n;j++) map[i][j]=i!=j; for(i=1;i<=m;i++){ scanf("%d%d",&u,&v); map[u][v]=0; map[v][u]=0; } connect.clear(); cnt=top=pop=len=0; for(i=1;i<=n;i++){ dfn[i]=-1; as[i]=0; edge[i].clear(); } for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(map[i][j]) edge[i].push_back(j); for(i=1;i<=n;i++) if(dfn[i]==-1) biconnect(i); for(i=0;i<connect.size();i++){ for(j=1;j<=n;j++)vis[j]=bif[j]=0; make(connect[i]); } m=n; for(i=1;i<=n;i++)m-=as[i]; printf("%d\n",m); } return 0; }