缩点
CF1239DCatowice City 题解
( t Tarjan) 巧妙图论转化题。
P.S.
- 模板
//Tarjan
int cnt,dfn[T],low[T],ct,team[T],cs,st[T];
bool inq[T];
void Tarjan(int u){
dfn[u]=low[u]=cnt++,st[cs++]=u,inq[u]=true;
for(int v:e[u])
if(!~dfn[v]) Tarjan(v),low[u]=min(low[u],low[v]);
else if(inq[v]) low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])for(int v=-1,t=cnt++;v!=u;)
v=st[--cs],team[v]=t,inq[v]=false;
}
桥
P.S.
- 模板
//Data
const int N=1e5;
int n,m,ans;
vector<int> e[N];
//Tarjan
int cnt,low[N],dfn[N];
void Tarjan(int u,int fa){
// cout<<"Tarjan("<<u<<","<<fa<<")
";
low[u]=dfn[u]=cnt++;
for(int&v:e[u])if(v!=fa)
if(!~dfn[v]) {
Tarjan(v,u),low[u]=min(low[u],low[v]);
if(dfn[u]<low[v]) ans++;
} else low[u]=min(low[u],dfn[v]);
}
//Main
int main(){
cin>>n>>m;
for(int i=0;i<n;i++) dfn[i]=low[i]=-1;
for(int i=0;i<m;i++){
int u,v; cin>>u>>v;
u--,v--,e[u].pb(v),e[v].pb(u);
}
for(int i=0;i<n;i++)if(!~dfn[i]) Tarjan(i,-1);
cout<<ans<<'
';
return 0;
}
2-sat
不能解决如果 (a) 为 (x) 则 (b) 为 (y) 的问题,只能解决 (a) 为 (x) 或 (b) 为 (y) 的问题。
NOI2017 游戏 代码
因为3-sat是NP的,所以枚举每个 (x) 处不选 (A) 还是不选 (B)(这样就能包含所有情况),将题目中的一个条件转化为两个条件,然后处理一下跑2-sat。细节极多调死人。
POI2011 KON-Conspiracy 代码
把图分成完全图和空图方案数。如果两点有边则必有一点在完全图,无边则必有一点在空图,2-sat找出一种方案,然后分 (2) 种情况讨论:空图与完全图流通一个点、空图与完全图交换一个点,统计答案,记得加上选出方案。
P.S.
- 模板
//Data
const int N=1e6,T=N<<1;
int n,m;
int p(int x,int a){return x+a*n;}
vector<int> e[T];
//Tarjan
int cnt,dfn[T],low[T],ct,team[T],cs,st[T];
bool inq[T];
void Tarjan(int u){
dfn[u]=low[u]=cnt++,st[cs++]=u,inq[u]=true;
for(int v:e[u])
if(!~dfn[v]) Tarjan(v),low[u]=min(low[u],low[v]);
else if(inq[v]) low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])for(int v=-1,t=cnt++;v!=u;)
v=st[--cs],team[v]=t,inq[v]=false;
}
//Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<m;i++){
int x,a,y,b;
cin>>x>>a>>y>>b,--x,--y;
e[p(x,!a)].pb(p(y,b));
e[p(y,!b)].pb(p(x,a));
}
for(int i=0;i<(n<<1);i++)
dfn[i]=low[i]=team[i]=-1;
for(int i=0;i<(n<<1);i++)
if(!~dfn[i]) Tarjan(i);
for(int i=0;i<n;i++)if(team[i]==team[i+n])
cout<<"IMPOSSIBLE
",exit(0);
cout<<"POSSIBLE
";
for(int i=0;i<n;i++)
cout<<(team[i]>team[i+n])<<' ';
cout<<'
';
return 0;
}