dfs求字典序最小的2-sat解方法:
如果原图中的同一对点编号都是连续的(01、23、45……)则可以依次尝试第0对、第1对……点,每对点中先尝试编号小的,若失败再尝试编号大的。这样一定能求出字典序最小的解(如果有解的话),因为一个点一旦被确定,则不可更改。
如果原图中的同一对点编号不连续(比如03、25、14……)则按照该对点中编号小的点的编号递增顺序将每对点排序,然后依次扫描排序后的每对点,先尝试其编号小的点,若成功则将这个点选上,否则尝试编号大的点,若成功则选上,否则(都失败)无解。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N = 16100; const int MAXM = 40200; int n,m; bool mark[N]; int sta[N],top; struct Edge { int v,next; }es[MAXM]; int head[N]; int cnt=0; inline void add_edge(int u,int v) { es[++cnt].v=v; es[cnt].next=head[u]; head[u]=cnt; } bool dfs(int u) { if(mark[u^1]) return false; if(mark[u]) return true; sta[++top]=u; mark[u]=1; for(int i=head[u];~i;i=es[i].next) { int v=es[i].v; if(dfs(v)==false) return false; } return true; } bool judge() { for(int i=0;i<2*n;i++) { if(!mark[i]&&!mark[i^1]) { top=0; if(dfs(i)==false) { for(int j=1;j<=top;j++) mark[sta[j]]=0; top=0; if(dfs(i^1)==false) return false; } } } return true; } void ini() { memset(mark,0,sizeof(mark)); memset(head,-1,sizeof(head)); cnt=top=0; } int main() { while(~scanf("%d%d",&n,&m)) { ini(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); u--,v--; add_edge(u,v^1); add_edge(v,u^1); } if(judge()) { for(int i=0;i<2*n;i++) if(mark[i]) printf("%d\n",i+1); } else puts("NIE"); } return 0; }
时间: 2024-10-11 01:57:01