poj2942圆桌骑士【点双连通分量+二分图判断】
2015-11-18 09:49
357 查看
/*********** poj2942 2015.11.11-2015.11.13 不懂 暂时放下了 2015.11.18 4792K 1172MS G++ ***********/ #include <iostream> #include<cstdio> #include<cstring> #include<vector> #include<stack> #include<algorithm> using namespace std; #define maxn 1005 struct Edge { int u,v; }; int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;//pre[]表示开始时间 bccno[]表示某点所在集合号 bcc_cnt表示编号 vector<int>G[maxn],bcc[maxn]; stack<Edge>S; int dfs(int u,int fa) { int lowu=pre[u]=++dfs_clock;//记录访问时间 int child=0; for(int i=0;i<G[u].size();i++)//遍历与u点相连接的边 { int v=G[u][i]; Edge e=(Edge){u,v};//当前的点所连接的边 if(!pre[v]) { S.push(e); child++; int lowv=dfs(v,u);//后代 lowu=min(lowu,lowv);//用后代的low函数更新自己 if(lowv>=pre[u])//存在子节点连不回此点之前的点,此点是割点--定理 { iscut[u]=true;//标记为割点 bcc_cnt++; bcc[bcc_cnt].clear(); for(;;) { Edge x=S.top();S.pop(); if(bccno[x.u]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; } if(bccno[x.v]!=bcc_cnt)//防止加重 { bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u&&x.v==v) break; } } } else if(pre[v]<pre[u]&&v!=fa)//访问过v 而且v在u之前 { S.push(e); lowu=min(lowu,pre[v]);//用反向边更新自己 } } if(fa<0&&child==1) iscut[u]=0;//判断是根节点而且只有一个孩子那么不是割顶 return lowu;//返回后代序号 } void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); memset(bccno,0,sizeof(bccno)); dfs_clock=bcc_cnt=0; for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1); } int odd[maxn],color[maxn]; bool bipartite(int u,int b)//判断是否是二分图 { for(int i=0;i<G[u].size();i++)//遍历与这个点相连接的点 { int v=G[u][i]; if(bccno[v]!=b) continue;//不在同一个连通分量 跳过 if(color[v]==color[u]) return false; if(!color[v])//此点未遍历过 { color[v]=3-color[u];//此点颜色等于三减去与此点相连点的颜色 if(!bipartite(v,b)) return false; } } return true; } int A[maxn][maxn]; int main() { int kase=0,n,m; while(scanf("%d%d",&n,&m)==2&&n) { for(int i=0;i<n;i++) G[i].clear(); memset(A,0,sizeof(A)); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); u--;v--; A[u][v]=A[v][u]=1; } for(int u=0;u<n;u++) { for(int v=u+1;v<n;v++) if(!A[u][v]) { G[u].push_back(v); G[v].push_back(u); } } find_bcc(n); memset(odd,0,sizeof(odd)); //题目要求不在任何一个简单奇圈上的节点个数 for(int i=1;i<=bcc_cnt;i++) { memset(color,0,sizeof(color)); for(int j=0;j<bcc[i].size();j++) bccno[bcc[i][j]]=i;//主要处理割顶 int u=bcc[i][0]; color[u]=1;//u是这个连通分量的第一个点 if(!bipartite(u,i))//如果某个连通分量不是二分图 for(int j=0;j<bcc[i].size();j++) odd[bcc[i][j]]=1;//给其中所有节点标记在奇圈上 } int ans=n; for(int i=0;i<n;i++) if(odd[i]) ans--; printf("%d\n",ans); } return 0; }二分图的求法有待考究
相关文章推荐
- 安卓开发之Intent
- 关于UIViewController添加UINavigationBar的详细实现方法
- 程序猿必备的高逼格午饭玩具
- 10.php Html下利用php循环创建组件
- WatchConnectivity:通过Application Context同步最新数据
- 前台 post方法提交却变成了 get 方法
- 关于eclipse无法连接到手机的问题
- 利用classloader动态加载jar包
- android接入即时IM(接入亲加通信云)
- Chinco(摩客串串)——App原型交互演示利器
- Java序列化与反序列化
- PHP 底层的运行机制与原理
- Json 数据的解析 ,生成
- 谈编程是个什么玩意儿
- Xcode:CUICatalog: Invalid asset name supplied: (null)
- iOS开发60分钟入门
- 程序猿必备的高逼格午饭玩具
- mac中自动保存git用户名和密码
- Vectors For All (almost)
- 15省赛B-map容器