因为我要缓考复习,所以这周看的算法内容比较少,这周看了2-sat问题和部分差分约束,顺带复习了一下之前的Tarjan算法,感觉太久没看又忘得差不多了,所以要勤加复习才行。
2-sat问题:
n个集合给出一些限制条件,要求满足限制条件,且限制条件往往是要求满足a就不能满足b,或者相反,故可以用强联通分量法(tarjan算法)来做(还有染色法)
2-sat模板:
#include<bits/stdc++.h>
using namespace std;
int n,m,t,p,q;
int i,a,j,b;
int dfn[2000010],low[2000010],belong[2000010];
bool f[2000010];
vector<int> v[2000010];
stack<int> s;
void tarjan(int x)//求出强联通分量的拓扑序反序
{
int k;
dfn[x]=low[x]=++t;
f[x]=1;
s.push(x);
for(int i=0;i<v[x].size();i++)
{
k=v[x][i];
if(!dfn[k])
{
tarjan(k);
low[x]=min(low[x],low[k]);
}
else if(f[k])
{
low[x]=min(low[x],dfn[k]);
}
}
if(dfn[x]==low[x])
{
p++;
while(1)
{
q=s.top();
s.pop();
belong[q]=p;
f[q]=0;
if(q==x)
break;
}
}
}
int main()
{
cin>>n>>m;
//注意建图,详情看题解
for(int y=1;y<=m;y++)
{
cin>>i>>a>>j>>b;
if(a==1&&b==1)
{
v[i].push_back(j+n);
v[j].push_back(i+n);
}
if(a==0&&b==0)
{
v[i+n].push_back(j);
v[j+n].push_back(i);
}
if(a==1&&b==0)
{
v[i].push_back(j);
v[j+n].push_back(i+n);
}
if(a==0&&b==1)
{
v[i+n].push_back(j+n);
v[j].push_back(i);
}
}
for(int i=1;i<=2*n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
if(belong[i]==belong[i+n])
{
cout<<"IMPOSSIBLE"<<endl;
return 0;
}
}
cout<<"POSSIBLE"<<endl;
for(int i=1;i<=n;i++)
{
if(belong[i]>belong[i+n])
{
cout<<1<<' ';
}
else
{
cout<<0<<' ';
}
}
return 0;
}