题面
解析
2-sat裸题, 求字典序最小的解
我一开始试图用拓扑序求字典序最小的解,YY了一阵,打完代码,无论如何都要WA,于是弃疗了,至今不知为什么会错,也许是我太菜了吧,于是学习了一下dfs构造字典序最小解的方法,时间复杂度是O(nm)的
基本思路同拓扑序构造可行解一样,用染色法。但dfs是直接在原图中跑的,因此要传递选择的标记,也就是颜色。从小到大对每一个没有染色的点$j$尝试染上选择的颜色,在对称点$j'$(点$j$的编号小于点$j'$的编号)上染上不选的颜色,传递选择颜色时如果没有遇到不选的颜色,说明染色方案成功,否则失败,再给点$j'$染上选择的颜色 ,点$j$染上不选的颜色,进行相同操作,如果仍然失败,则说明该情况没有可行解。
HDU上有一个坑点:多组数据。(我的英语菜得不谈,这个东西搞了我半个小时)
代码:

#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 8006;
int n, m, stak[maxn], top, col[maxn<<1];
vector<int> G[maxn<<1];
int mir(int x)
{
return x&1? x+1: x-1;
}
bool paint(int x)
{
if(col[x])
return col[x] == 1;
col[x] = 1;col[mir(x)] = 2;
stak[++top] = x;
for(unsigned int i = 0; i < G[x].size(); ++i)
{
int id = G[x][i];
if(!paint(id))
return 0;
}
return 1;
}
bool work()
{
for(int i = 1; i <= (n<<1); ++i)
if(!col[i])
{
top = 0;
if(!paint(i))
{
while(top) col[stak[top]] = col[mir(stak[top])] = 0, top--;
if(!paint(mir(i)))
return 0;
}
}
return 1;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
for(int i = 1; i <= m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
G[x].push_back(mir(y));
G[y].push_back(mir(x));
}
if(work())
{
for(int i = 1; i <= (n<<1); ++i)
if(col[i] == 1)
printf("%d\n", i);
}
else
printf("NIE\n");
for(int i = 1; i <= (n<<1); ++i)
G[i].clear(), col[i] = 0;
}
return 0;
}
来源:https://www.cnblogs.com/Joker-Yza/p/11312672.html
