2-SAT总结

看到HDOJ上有一个2-SAT专题,刷完之后顺便总结一下。

最简单的2-SAT问题就是判断是否有解,回答YES或NO就行了,不需要输出具体的解。这种问题建图完毕后一个SCC(强连通分量)就好了。如果要输出解,就多一个拓扑排序。代码中涉及多次建图,注意细节就好了。

1.HDOJ 3062 Party

很裸的2-SAT模板,而且不用输出路径。
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #define mp make_pair #define MEMSET(a, b) memset(a, b, sizeof(a)) using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef pair 
                    
                      pii; typedef vector 
                     
                       vi; typedef vi::iterator vi_it; typedef map 
                      
                        mii; typedef priority_queue 
                       
                         pqi; typedef priority_queue 
                        
                          , greater 
                         
                           > rpqi; const int MAX_N = 2000 + 10; int link[MAX_N][MAX_N], rlink[MAX_N][MAX_N]; int stk[MAX_N]; bool vis[MAX_N]; int belong[MAX_N]; int top, cnt; void dfs_visit(int (*lk)[MAX_N], int u, bool ft) { vis[u] = true; for (int i = 1; i <= lk[u][0]; ++i) { if (!vis[lk[u][i]]) { dfs_visit(lk, lk[u][i], ft); } } if (ft) { stk[top++] = u; } else { belong[u] = cnt; } } void scc(int n) { top = 0; MEMSET(vis, 0); for (int i = 0; i < n; ++i) { if (!vis[i]) { dfs_visit(link, i, true); } } cnt = 0; MEMSET(vis, 0); while (top) { if (!vis[stk[--top]]) { dfs_visit(rlink, stk[top], false); ++cnt; } } } bool two_sat(int n) { scc(n << 1); for (int i = 0; i < n; ++i) { if (belong[i] == belong[i + n]) { return false; } } return true; } int main(int argc, char *argv[]) { int n, m, i, a1, a2, c1, c2; while (cin >> n >> m) { for (i = 0; i < (n << 1); ++i) { rlink[i][0] = link[i][0] = 0; } while (m--) { scanf("%d%d%d%d", &a1, &a2, &c1, &c2); int b1 = a1 + n * (c1 ^ 1); int b2 = a2 + n * (c2 ^ 1); a1 += n * c1; a2 += n * c2; link[a1][++link[a1][0]] = b2; link[a2][++link[a2][0]] = b1; rlink[b2][++rlink[b2][0]] = a1; rlink[b1][++rlink[b1][0]] = a2; } if (two_sat(n)) { puts("YES"); } else { puts("NO"); } } return 0; } 
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
        
       
       
      
      
     
     
    
    

这个题要求输出一组解,另外需要根据区间的交来建图,代码比较长。判断区间是否相交时我先排序,这样内层循环不用遍历所有j,不过效率其实差不多,只快了一点点。。。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
         #include 
         
           #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #define mp make_pair #define X first #define Y second #define MEMSET(a, b) memset(a, b, sizeof(a)) using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef pair 
                    
                      pii; typedef vector 
                     
                       vi; typedef vi::iterator vi_it; typedef map 
                      
                        mii; typedef priority_queue 
                       
                         pqi; typedef priority_queue 
                        
                          , greater 
                         
                           > rpqi; const int MAX_N = 2000 + 10; int link[MAX_N][MAX_N], rlink[MAX_N][MAX_N]; int stk[MAX_N], ans[MAX_N], op[MAX_N]; bool vis[MAX_N], flag[MAX_N][MAX_N]; int belong[MAX_N]; int top, cnt; pair 
                          
                            cere[MAX_N]; void dfs_visit(int (*lk)[MAX_N], int u, bool ft) { vis[u] = true; for (int i = 1; i <= lk[u][0]; ++i) { if (!vis[lk[u][i]]) { dfs_visit(lk, lk[u][i], ft); } } if (ft) { stk[top++] = u; } else { belong[u] = cnt; } } void scc(int n) { top = 0; MEMSET(vis, 0); for (int i = 0; i < n; ++i) { if (!vis[i]) { dfs_visit(link, i, true); } } cnt = 0; MEMSET(vis, 0); while (top) { if (!vis[stk[--top]]) { dfs_visit(rlink, stk[top], false); ++cnt; } } } bool two_sat(int n) { scc(n << 1); for (int i = 0; i < n + n; i += 2) { if (belong[i] == belong[i + 1]) { return false; } } return true; } void color(int u) { ans[u] = 2; for (int i = 1; i <= rlink[u][0]; ++i) { if (!ans[rlink[u][i]]) { color(rlink[u][i]); } } } bool cmp(const pair 
                           
                             &p1, const pair 
                            
                              &p2) { return p1.Y < p2.Y; } int main(int argc, char *argv[]) { // freopen("D:\\in.txt", "r", stdin); int n, i, j; cin >> n; for (i = 0; i < n; ++i) { int s1, s2, t1, t2, d; scanf("%d:%d %d:%d %d", &s1, &s2, &t1, &t2, &d); cere[i + i] = mp(mp(s1 * 60 + s2, s1 * 60 + s2 + d), i + i); cere[i + i + 1] = mp(mp(t1 * 60 + t2 - d, t1 * 60 + t2), i + i + 1); } sort(cere, cere + n + n); for (i = 0; i < n + n; ++i) { for (j = i + 1; j < n + n && cere[j].X.X < cere[i].X.Y; ++j) { int u = cere[i].Y, v = cere[j].Y ^ 1; if (!flag[u][v]) { flag[u][v] = true; link[u][++link[u][0]] = v; rlink[v][++rlink[v][0]] = u; } u = cere[j].Y, v = cere[i].Y ^ 1; if (!flag[u][v]) { flag[u][v] = true; link[u][++link[u][0]] = v; rlink[v][++rlink[v][0]] = u; } } } if (!two_sat(n)) { puts("NO"); return 0; } else { puts("YES"); } MEMSET(flag, 0); for (i = 0; i < n + n; ++i) { rlink[i][0] = 0; op[belong[i]] = belong[i ^ 1]; } for (i = 0; i < n + n; ++i) { int u = belong[i]; for (j = 1; j <= link[i][0]; ++j) { int v = belong[link[i][j]]; if (u != v && !flag[v][u]) { flag[v][u] = true; rlink[v][++rlink[v][0]] = u; } } } MEMSET(vis, 0); top = 0; for (i = 0; i < cnt; ++i) { if (!vis[i]) { dfs_visit(rlink, i, true); } } while (top) { if (!ans[stk[--top]]) { ans[stk[top]] = 1; color(op[stk[top]]); } } sort(cere, cere + n + n, cmp); for (i = 0; i < n + n; ++i) { if (ans[belong[i]] == 1) { printf("%02d:%02d %02d:%02d\n", cere[i].X.X / 60, cere[i].X.X % 60, cere[i].X.Y / 60, cere[i].X.Y % 60); } } return 0; } 
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
       
      
      
     
     
    
    
   
   

和上题差不多的。
#include 
   
   
    
    
#include 
    
    
     
     
 
const int maxn=10010;
int n, m, nxt[maxn], head[maxn], pnt[maxn], ne, e, a, b, a0, b0;
char c1, c2;
int nnxt[maxn], nhead[maxn], npnt[maxn];
int order[maxn], norder, id[maxn], v[maxn];
int ans[maxn], op[maxn];
 
void dfs(int d){
    v[d] = 1;
    for(int i=head[d]; i!=-1; i=nxt[i])
        if(!v[pnt[i]])
            dfs(pnt[i]);
    order[norder++] = d;
}
void ndfs(int d, int k){
    v[d] = 1;
    id[d] = k;
    for(int i=nhead[d]; i!=-1; i=nnxt[i])
        if(!v[npnt[i]])
            ndfs(npnt[i], k);
}
void addedge(int s, int t){
    pnt[e] = t; nxt[e] = head[s]; head[s] = e++;
}
void addnedge(int t, int s){
    npnt[ne] = s; nnxt[ne] = nhead[t]; nhead[t] = ne++;
}
void color(int d){
    ans[d] = 2;
    for(int i=head[d]; i!=-1; i=nxt[i])
        if(!ans[pnt[i]])
            color(pnt[i]);
}
int main(){
    while(1){
        norder = e = ne = 0;
        memset(head, -1, sizeof head);
        memset(nhead, -1, sizeof nhead);
        scanf("%d%d", &n, &m);
        if(!n&&!m)
            break;
        for(int i=0; i
     
     
      
      =0; --i)
            if(!v[order[i]])
                ndfs(order[i], k++);
        int mark = 1;
        for(int i=0; i
      
      
       
       =0; --i)
            if(!ans[order[i]]){
                ans[order[i]] = 1;
                color(op[order[i]]);
            }
        for(int i=1; i
       
       
      
      
     
     
    
    
   
   

4.HDOJ 3715 Go Deeper

二分答案之后判断2-SAT问题是否有解。SCC用tarjan写的。

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #include 
                    
                      #define mp make_pair #define X first #define Y second #define MEMSET(a, b) memset(a, b, sizeof(a)) using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef pair 
                     
                       pii; typedef vector 
                      
                        vi; typedef vi::iterator vi_it; typedef map 
                       
                         mii; typedef priority_queue 
                        
                          pqi; typedef priority_queue 
                         
                           , greater 
                          
                            > rpqi; const int MAX_N = 20000 + 10; int head[MAX_N]; int edge[MAX_N * 100][2]; int dfn[MAX_N], low[MAX_N]; int stk[MAX_N]; int belong[MAX_N]; int top, cnt, idx, edgecnt; int a[MAX_N], b[MAX_N], c[MAX_N]; int N; void dfs(int u) { dfn[u] = low[u] = ++idx; stk[top++] = u; int v; for (int i = head[u]; i != -1; i = edge[i][1]) { if (!dfn[v = edge[i][0]]) { dfs(v); low[u] = min(low[u], low[v]); } else if (!belong[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { belong[u] = ++cnt; while (stk[--top] != u) { belong[stk[top]] = cnt; } } } void tarjan(int n) { MEMSET(belong, 0); MEMSET(dfn, 0); cnt = idx = top = 0; for (int i = 1; i <= n; ++i) { if (!dfn[i]) { dfs(i); } } } bool two_sat(int n) { tarjan(n + n); for (int i = 1; i <= n; ++i) { if (belong[i] == belong[i + n]) { return false; } } return true; } inline void add_edge(int u, int v) { edge[edgecnt][0] = v; edge[edgecnt][1] = head[u]; head[u] = edgecnt++; } void build(int n) { int i; MEMSET(head, -1); edgecnt = 0; for (i = 1; i <= n; ++i) { if (c[i] == 0) { add_edge(a[i], b[i] + N); add_edge(b[i], a[i] + N); } else if (c[i] == 1) { add_edge(a[i], b[i]); add_edge(b[i], a[i]); add_edge(a[i] + N, b[i] + N); add_edge(b[i] + N, a[i] + N); } else { add_edge(a[i] + N, b[i]); add_edge(b[i] + N, a[i]); } } } int main(int argc, char *argv[]) { // freopen("D:\\in.txt", "r", stdin); int t, n, m, i, j; cin >> t; while (t--) { scanf("%d%d", &n, &m); N = n; for (i = 1; i <= m; ++i) { scanf("%d%d%d", a + i, b + i, c + i); } int low = 0, high = m, ans = 0; while (low <= high) { int mid = (low + high) >> 1; build(mid); if (two_sat(N)) { low = mid + 1; ans = mid; } else { high = mid - 1; } } printf("%d\n", ans); } return 0; } 
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
        
       
       
      
      
     
     
    
    

5.POJ 3207 Ikki's Story IV - Panda's Trick

也是只需要判断,不过注意弦相交的判断方法。

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #define mp make_pair #define MEMSET(a, b) memset(a, b, sizeof(a)) using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef pair 
                    
                      pii; typedef vector 
                     
                       vi; typedef vi::iterator vi_it; typedef map 
                      
                        mii; typedef priority_queue 
                       
                         pqi; typedef priority_queue 
                        
                          , greater 
                         
                           > rpqi; const int MAX_M = 1000 + 2; int line[MAX_M][2]; vector 
                          
                            link[MAX_M]; int dfn[MAX_M], low[MAX_M], belong[MAX_M]; int stk[MAX_M]; int cnt = 0, top = 0, idx = 0; bool intersect(int *a, int *b, int n) { if (a[0] < b[0] && b[0] < a[1] && a[1] < b[1]) { return true; } if (b[0] < a[0] && a[0] < b[1] && b[1] < a[1]) { return true; } return false; } void dfs(int u) { dfn[u] = low[u] = ++idx; stk[top++] = u; int v; for (int i = 0; i < link[u].size(); ++i) { if (!dfn[v = link[u][i]]) { dfs(v); low[u] = min(low[u], low[v]); } else if (!belong[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { belong[u] = ++cnt; while (stk[--top] != u) { belong[stk[top]] = cnt; } } } void tarjan(int n) { for (int i = 0; i < n; ++i) { if (!dfn[i]) { dfs(i); } } } bool two_sat(int n) { tarjan(n + n); for (int i = 0; i < n; ++i) { if (belong[i] == belong[i + n]) { return false; } } return true; } int main(int argc, char *argv[]) { // freopen("D:\\in.txt", "r", stdin); int n, m; cin >> n >> m; for (int i = 0; i < m; ++i) { cin >> line[i][0] >> line[i][1]; if (line[i][0] > line[i][1]) { swap(line[i][0], line[i][1]); } for (int j = 0; j < i; ++j) { if (intersect(line[i], line[j], n)) { link[i].push_back(j + m); link[j].push_back(i + m); link[i + m].push_back(j); link[j + m].push_back(i); } } } if (two_sat(m)) { puts("panda is telling the truth..."); } else { puts("the evil panda is lying again"); } return 0; } 
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
        
       
       
      
      
     
     
    
    

下面几题还没做,先给出链接




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值