http://poj.org/problem?id=2942
思路:首先考虑建边,但是会发现直接建边很难处理。
那么考虑通过能相邻的图去建立边.建完边后结合题意,题目说要求一些骑士永远不可能去开会。开会的要求有一个>=3的奇环。
所以题目问的是哪些骑士是不在任何一个奇环里的。
所以考虑把补图上所有的缩点后的点联通分量里面判一下奇环。
奇环的判定也就是染色法判定是不是二分图。
这个题大概调了5小时。
做了之后发现点连通分量的板子是不一样的,因为割点是属于多个连通分量里面的,不能直接按照求强连通分量的缩点那样直接弹出栈。
另外注意在主函数里面把每个dcc[]打上对应的编号,然后在判奇数环的时候注意在补图上判奇数环,dcc[]里面是没有连边关系的。同时注意遍历点的时候是要在同一个dcc[]里的
提供一组数据:
7 12
1 7
2 1
3 6
7 6
1 4
4 7
4 2
1 5
2 3
2 7
6 5
5 3
0 0
ans:7
http://poj.org/bbs?problem_id=2942(更多的见discuss)
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e3+100;
typedef int LL;
bool ma[maxn][maxn];///表示不能相邻的图
stack<LL>s;
vector<LL>g[maxn];//补图
vector<LL>dcc[maxn];
LL dfn[maxn],low[maxn],times=0,cnt=0,fa[maxn],id[maxn];
bool ge[maxn],oddcircle[maxn];///奇环上的标记
LL col[maxn];//二分图染色 1--黑;2---白
void init1(){
times=0;cnt=0;
for(LL i=0;i<maxn;i++) g[i].clear(),dcc[i].clear();
memset(ma,0,sizeof(ma));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(fa,-1,sizeof(fa));
memset(ge,0,sizeof(ge));
memset(oddcircle,0,sizeof(oddcircle));
memset(id,0,sizeof(id));
}
bool flag=1;
void init2()
{
flag=1;
memset(col,0,sizeof(col));
}
void tarjan2(LL x)
{
dfn[x]=low[x]=++times;
s.push(x);
LL child=0;
if(fa[x]==-1&&g[x].size()==0){
dcc[++cnt].push_back(x);
return;
}
for(LL i=0;i<g[x].size();i++){
LL to=g[x][i];
if(!dfn[to])
{
fa[to]=x;child++;
tarjan2(to);
low[x]=min(low[x],low[to]);
if(low[to]>=dfn[x])
{
child++;
if(fa[x]!=-1||child>1) ge[x]=true;
cnt++;
LL z;
do{
z=s.top();s.pop();
dcc[cnt].push_back(z);
}while(z!=to);
dcc[cnt].push_back(x);
}
}
else if(to!=fa[x]) low[x]=min(low[x],dfn[to]);
}
}
void dfs(LL u,LL color)//注意二分图要找一整个dcc图中是不是存在奇数度的环
{
col[u]=color;
///cout<<"col["<<u<<"]="<<color<<endl;
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(id[u]!=id[v]) continue;//不在染色的dcc上
if(col[v]==col[u]){
flag=0;break;
}
else if(!col[v]){
dfs(v,3-color);
}
}
}
bool check(LL x)
{
init2();
dfs(x,1);
/// LL q=id[x];
// cout<<"id:"<<endl;
/// for(LL i=0;i<dcc[q].size();i++){
/// cout<<id[dcc[q][i]]<<" ";
/// }
/// cout<<endl;
///cout<<"染色"<<endl;
///for(LL i=0;i<dcc[q].size();i++){
/// cout<<col[dcc[q][i]]<<" ";
///}
///cout<<endl;
if( flag==0) {
///cout<<"是奇环"<<endl;
return true;
}
else {
/// cout<<"不是奇环"<<endl;
return false;
}
}
int main(void)
{
LL n,m;
while(scanf("%d%d",&n,&m)&&(n+m))
{
init1();
for(LL i=1;i<=m;i++){
LL x,y;scanf("%d%d",&x,&y);
ma[x][y]=1;ma[y][x]=1;
}
for(LL i=1;i<=n;i++){
for(LL j=i+1;j<=n;j++)
{
if(!ma[i][j]) g[i].push_back(j),g[j].push_back(i);
}
}
for(LL i=1;i<=n;i++){
if(!dfn[i]) tarjan2(i);
}
/// cout<<"dcc的数量:"<<cnt<<endl;
/// for(LL i=1;i<=cnt;i++){
/// cout<<"dcc["<<i<<"]="<<dcc[i].size()<<": ";
/// for(LL j=0;j<dcc[i].size();j++)
/// {
// cout<<dcc[i][j]<<" ";
// }
/// cout<<endl;
}
for(LL i=1;i<=cnt;i++){
for(LL j=0;j<dcc[i].size();j++) id[dcc[i][j]]=i;
if(dcc[i].size()>=3&&check(dcc[i][0])==true){
for(LL j=0;j<dcc[i].size();j++)
{
/// cout<<"是奇环"<<endl;
oddcircle[dcc[i][j]]=true;
}
}
}
LL sum=0;
for(LL i=1;i<=n;i++){
if(oddcircle[i]==1) sum++;
}
printf("%d\n",n-sum);
}
return 0;
}