• LA3713 2-sat(用到两种矛盾关系)


      1 /*LA3713
      2 典型的2-sat模型
      3 宇航员分两类:
      4 1、年龄少于平均 young
      5 2、至少为平均
      6 矛盾:
      7 情况一:如果两个宇航员属于同一类且相互矛盾的话,则他们两个的选择一定是不相同的
      8 情况二:如果不属于同一组相互矛盾,不能同时选C任务
      9 建模:A/B 2*i
     10       C  2*i+1
     11 情况一:2x-->2y+1,2x+1-->2y;2y-->2x+1;2y+1-->2x;
     12 情况二:2x+1-->2y,2y+1-->2x;
     13 
     14 */
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <math.h>
     19 #include <ctype.h>
     20 #include <string>
     21 #include <iostream>
     22 #include <sstream>
     23 #include <vector>
     24 #include <queue>
     25 #include <stack>
     26 #include <map>
     27 #include <list>
     28 #include <set>
     29 #include <algorithm>
     30 #define INF 0x3f3f3f3f
     31 #define LL long long
     32 #define eps 1e-4
     33 #define maxn 100010
     34 using namespace std;
     35 int Age[maxn];
     36 int n,m;
     37 double Aver;
     38 int nextint(){int x;scanf("%d",&x);return x;}
     39 int kind(int age)
     40 {
     41     if (Aver-age>eps) return 2;else return 1;//B:young
     42 }
     43 struct TwoSAT
     44 {
     45     int n;
     46     vector<int> G[maxn*2];
     47     bool mark[maxn*2];//联系《2-sat算法解析》中的红蓝标色
     48     int S[maxn*2],c;
     49     bool dfs(int x)
     50     {
     51         if (mark[x^1]) return false;//真假同时被标记,逻辑矛盾
     52         if (mark[x]) return true;//x被标记,意味着下面的节点也被标记,思想是记忆化搜索
     53         mark[x]=true;
     54         S[c++]=x;
     55         for(int i=0; i<G[x].size(); i++)
     56         if(!dfs(G[x][i])) return false; //同一个强联通分量应该表上同一种颜色
     57         return true;
     58     }
     59     void init(int n)
     60     {
     61         this->n=n;
     62         for(int i=0; i<n*2; i++) G[i].clear();
     63         memset(mark,0,sizeof(mark));
     64     }
     65     //x=xval or y=xval ,x 则 xval=0,x'则xval=1
     66     void add_clause(int x ,int y,int k)
     67     {
     68         if(k==0){
     69         G[2*x+1].push_back(2*y);
     70         G[2*y+1].push_back(2*x);
     71         }
     72         if (k==1){
     73         G[2*x].push_back(2*y+1);
     74         G[2*y].push_back(2*x+1);
     75         }
     76     }
     77     bool solve()
     78     {
     79         for(int i=0;i<n*2;i+=2)
     80         {
     81             if(!mark[i] && !mark[i^1])//真假都没被标记才需dfs,思考一下,原书上写的是[mark+1],这是由i的取值和步长决定的,这里更改,使逻辑含义统一
     82             {
     83                 c=0;//记得清零
     84                 if(!dfs(i))//将i标记为true
     85                 {
     86                     while(c>0) mark[S[--c]]=false;
     87                     if (!dfs(i^1)) return false;//更改初始标号颜色。只要有一个对象不能“二选一”,则2-sat无解
     88                 }
     89             }
     90         }
     91         return true;
     92     }
     93     void printans()
     94     {
     95         for(int i=0;i<n;i++)
     96         if (mark[2*i]) printf("%c
    ",'A'+kind(Age[i])-1);else printf("C
    ");
     97     }
     98 } sat;
     99 void read()
    100 {
    101     Aver=0;
    102     for(int i=0;i<n;i++) {Age[i]=nextint();Aver+=Age[i];}
    103 //    cout<<"a="<<Aver<<endl;
    104     Aver=Aver/n;
    105 //    cout<<"a="<<Aver<<endl;
    106 }
    107 void solve()
    108 {
    109     sat.init(n);
    110     for(int i=0;i<m;i++)
    111     {
    112         int x,y;
    113         x=nextint();y=nextint();
    114         x--;y--;
    115         if(kind(Age[x])==kind(Age[y]))
    116         {//2x-->2y+1,2x+1-->2y;2y-->2x+1;2y+1-->2x;//后面的0/1表示连边的方式
    117             sat.add_clause(x,y,1);
    118             sat.add_clause(x,y,0);
    119         }else
    120         {//2x+1-->2y,2y+1-->2x;
    121             sat.add_clause(x,y,0);
    122         }
    123     }
    124     if(sat.solve()) sat.printans();else printf("No solution.
    ");
    125 }
    126 int main()
    127 {
    128     while(cin>>n>>m)
    129     {
    130         if (n==0 && m==0) break;
    131         read();
    132         solve();
    133     }
    134     return 0;
    135 }
  • 相关阅读:
    为什么要前后端分离?有什么优缺点
    剑指offer-面试题21.包含min函数的栈
    操作系统典型调度算法
    那些年的那些事CISC和RISC发展中的纠缠
    基于MFC与第三方类CWebPage的百度地图API开发范例
    Linux进程通信----匿名管道
    续前篇-关于逆波兰表达式的计算
    逆波兰表达式的实现(也叫后缀表达式)
    剑指offer-面试题20.顺时针打印矩阵
    剑指offer-面试题.二叉树的镜像
  • 原文地址:https://www.cnblogs.com/little-w/p/3585637.html
Copyright © 2020-2023  润新知