http://acm.hdu.edu.cn/showproblem.php?pid=1814
这题搞了我半天。。。。而且似乎不需要用tarjan求强连通分量,直接暴力dfs就行了。。。
从前向后dfs,假设(1,2)中选择了1号点,那么取图中dfs,所有能够到达的点都要选,那么每到一个点就判断一下,如果没有必选,那么就必选,如果已经必选了,说明在这个点之前已经dfs过这里了,就直接return true,如果他的对立点opp(u)被标记为必选,说明这个点是不能选的。
复杂度为O(n.m)n=8000,m=20000,这过得也太艰难了。。。
#include<bits/stdc++.h>
using namespace std;
const int maxl=16000+10;
int n,m,top,ind,ans,ff,thisok;
int dfn[maxl],low[maxl],f[maxl],s[maxl];
vector<int> e[maxl],tmp;
bool in[maxl],vis[maxl],col[maxl];
inline int opp(int x)
{
if(x&1) return x+1;
else return x-1;
}
inline void prework()
{
top=0;ind=0;ff=0;
for(int i=1;i<=2*n;i++)
{
dfn[i]=low[i]=f[i]=0;col[i]=false;
in[i]=false,e[i].clear();vis[i]=false;
}
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(opp(v));
e[v].push_back(opp(u));
}
}
inline void tarjan(int u)
{
dfn[u]=low[u]=++ind;in[u]=true;s[++top]=u;
for(auto v : e[u])
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in[v])
low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])
{
int v;ff++;
do
{
v=s[top--];
f[v]=ff;in[v]=false;
}while(u!=v);
}
}
inline bool dfs(int u)
{
if(col[opp(u)])
return false;
if(col[u])
return true;
col[u]=true;tmp.push_back(u);
for(auto v : e[u])
if(!dfs(v))
return false;
return true;
}
inline void mainwork()
{
for(int i=1;i<=2*n;i++)
if(!dfn[i])
tarjan(i);
ans=1;
for(int i=1;i<=2*n;i+=2)
if(f[i]==f[i+1])
{
ans=0;
return;
}
for(int i=1;i<=2*n;i+=2)
if(col[i]==false && col[i+1]==false)
{
tmp.clear();
if(!dfs(i))
{
for(auto u : tmp)
col[u]=false;
tmp.clear();
if(!dfs(i+1))
{
ans=0;
return;
}
}
}
}
inline void print()
{
if(!ans)
puts("NIE");
else
{
for(int i=1;i<=2*n;i++)
if(col[i]==1)
printf("%d\n",i);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}