题面
解析
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 ", i); } else printf("NIE "); for(int i = 1; i <= (n<<1); ++i) G[i].clear(), col[i] = 0; } return 0; }