(转)2-SAT小结

2-sat小结


原文作者:老K
原文传送门


2-sat是什么

一类问题是这样的:

(两个符号的意思 \(\lor \ or,\land \ and\)

有n个布尔变量,现在对它们做出限制,比如\(a_i=1,a_i \lor a_j=1\),求一组可行的解。

假设限制元素最多的限制限制了k个元素,这个问题就被称为k-sat问题。

可以证明(然而我不会),\(k>2\)时是NPC的。


基础想法

把每个变量\(a_i\)拆成2个点\(i_0,i_1\),表示它为1或0

每个变量就变成了一个集合。要求在每个集合里选一个元素,满足所有限制。

然后有向边\(<u,v>\)表示若选u则选v。

\(a_i=1\)型限制

\(<i_0,i_1>\)

\(a_i=0\)则反过来。

\(a_i=a_j\)限制

\(<i_0,j_0><j_0,i_0><i_1,j_1><j_1,i_1>\)

\(a_i\not=a_j\)限制

\(<i_0,j_1><j_0,i_1><i_1,j_0><j_1,i_0>\)

\(a_i\lor a_j=1\)或者\(a_i\land a_j =0\)限制

对于前者,连\(<i_0,j_1><j_0,i_1>\)

后者显然是交换0,1

\(a_i\lor a_j=0\)或者\(a_i\land a_j =1\) 限制

拆开,转化为\(a_i=1\)型限制

其实都很显然是吧。


算法1

有一个很显然的结论:设\(u'\)表示u所在集合的另一个元素。

如果存在\(<u,v>\)则一定存在\(<v',u'>\)(对称性)

那么我们可以按照顺序枚举每一个布尔变量。

假设它是0,然后沿着单向边计算它影响的元素,如果没有问题就是0,并且计算它影响的元素的值。

否则假设它是1,如果没问题就是1,并且计算它影响元素的值。

否则无解。

由于对称性以及边是单向的,可以证明这个算法的正确性。(或者感性理解)

时间复杂度\(O(nm)\)其中n是点数m是边数。

当然0,1的顺序是可以交换的。

这个算法可以求出字典序最小的解。

在算之前,按照每个变量0,1编号较小值从小到大排序。

然后枚举要先枚举每个变量编号较小的那个点。


算法2

有没有更快的算法呢?

当然是有的。

我们可以先tarjan 强连通分量缩点。

那么同一个强连通分量里,点的选择情况是一样的(选则都选,不选则都不选)。

由对称性可知如果\(u,v\)在同一个强连通分量里,那么\(u',v'\)也在同一个强连通分量里。

如果\(u,u'\)在同一个强连通分量里,那么无解。

否则考虑,缩完点后得到了一个DAG,由两个边相反的DAG组成。

我们可以通过拓扑排序,每次找一个没有出边的分量,如果它里面点的对称点没有被选择,那么执行如下操作:

选择它里面的所有点。

把它扔掉。(把所有到它的边断掉)

可以发现是对的。

时间复杂度\(O(n+m)\),通常用来计算可行解或者判断可行性。


算法3(黑科技)

不难发现,在缩完点后,如果u能到达v,那么在tarjan 中,u一定在v之后被找到。

于是我们可以在拓扑排序中,每次取能取的,编号最小的分量,

显然,如果一个分量\(u\)和分量\(v\)是对称的,那么如果\(u<v\),会选择u,否则会选择v。

那么就不用重建图拓扑排序了。

常数优化/代码量优化效果还是很明显的。


例题

满汉全席

模板题。


NOI 2017 Day2T1 游戏

之所以用UOJ是因为ex test巨强无比。

发现有一些地图是X,3种都可以,但是个数不超过8.

我们可以把X转化为A或B。

枚举每个X转化为A还是B,跑2-SAT就可以了。

/*
Authlor: CNYALI_LK
LANG: C++
PROG: 317.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<int,int> pii;
template<class T>int chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>int chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
int read(){
    int s=0,base=1;
    char c;
    while(!isdigit(c=getchar()))if(c=='-')base=-base;
    while(isdigit(c)){s=s*10+(c^48);c=getchar();}
    return s*base;
}
char rc(){
    char c;
    while(!isalpha(c=getchar()));
    return c;
}
void rs(char *s){
    while(!isalpha(*s=getchar()))++s;
    while(isalpha(*s))*(++s)=getchar();
    *s=0;
}
char WriteIntBuffer[1024];
template<class T>void write(T a,char end){
    int cnt=0,fu=1;
    if(a<0){putchar('-');fu=-1;}
    do{WriteIntBuffer[++cnt]=fu*(a%10)+'0';a/=10;}while(a);
    while(cnt){putchar(WriteIntBuffer[cnt]);--cnt;}
    putchar(end);
}
struct _limit{
    int a,b,ax,bx;
};
_limit a[102424];
char s[102424];
_limit limit(){
    _limit x;
    x.a=read()-1;
    x.ax=rc();
    x.b=read()-1;
    x.bx=rc();
    return x;
}
int h[102424];
int beg[102424],to[233333],lst[233333],dfn[102423],low[102423],no[102423]; 
int blocks,e,t;
void add(int u,int v){
    to[++e]=v;
    lst[e]=beg[u];
    beg[u]=e;
}
int stk[102424],*top=stk;
void dfs(int x){
    dfn[x]=low[x]=++t;
    *(++top)=x;
    flor(int i=beg[x];i;i=lst[i])
        if(dfn[to[i]]){
            if(!no[to[i]])
                chkmin(low[x],dfn[to[i]]);
        }else{
            dfs(to[i]);
            chkmin(low[x],low[to[i]]);
        }
    if(dfn[x]==low[x]){
        ++blocks;
        do{
            no[*(--top+1)]=blocks;
        }while(*(top+1)!=x);
    }
}

int main(){
#ifdef cnyali_lk
    freopen("317.in","r",stdin);
    freopen("317.out","w",stdout);
#endif
    int n,d,m;
    n=read();
    d=read();
    rs(s);
    int xs=0;
    flor(int i=0;i<n;++i){
        if(s[i]=='x'){h[xs]=i;++xs;}
    }
    m=read();
    flor(int i=1;i<=m;++i){
        a[i]=limit();
    }
    int un=1<<d,u,v;
    flor(int j=0;j<un;++j){
        flor(int i=0;i<d;++i)s[h[i]]='a'+!!(j&(1<<i));
        flor(int i=0;i<n+n;++i)beg[i]=dfn[i]=low[i]=no[i]=0;
        blocks=e=t=0;   
        flor(int i=1;i<=m;++i){
            if(a[i].ax-'A'==s[a[i].a]-'a')continue;
            if(a[i].bx-'A'==s[a[i].b]-'a'){
                int u=a[i].a*2+(a[i].ax-'A'-(a[i].ax-'A'>=s[a[i].a]-'a'));
                add(u,u^1);
            }
            else{
                int u=a[i].a*2+(a[i].ax-'A'-(a[i].ax-'A'>=s[a[i].a]-'a'));
                int v=a[i].b*2+(a[i].bx-'A'-(a[i].bx-'A'>=s[a[i].b]-'a'));
                add(u,v);
                add(v^1,u^1);
            }
        }
        flor(int i=0;i<n+n;++i)if(!dfn[i])dfs(i);
        int ok=1;
        flor(int i=0;i<n;++i)if(no[i<<1]==no[i<<1|1])ok=0;
        if(ok){
            flor(int i=0;i<n;++i){
                int ans=(no[i<<1]>no[i<<1|1]);
                ans+=(ans>=s[i]-'a');
                putchar(ans+'A');
            }
            return 0;
        }
    }
    printf("-1\n");
    return 0;
}

\({\Huge\color{Gold}{老K太强了QAQ}}\)

转载于:https://www.cnblogs.com/enceladus-return0/p/9594098.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于微信小程序的家政服务预约系统采用PHP语言和微信小程序技术,数据库采用Mysql,运行软件为微信开发者工具。本系统实现了管理员和客户、员工三个角色的功能。管理员的功能为客户管理、员工管理、家政服务管理、服务预约管理、员工风采管理、客户需求管理、接单管理等。客户的功能为查看家政服务进行预约和发布自己的需求以及管理预约信息和接单信息等。员工可以查看预约信息和进行接单。本系统实现了网上预约家政服务的流程化管理,可以帮助工作人员的管理工作和帮助客户查询家政服务的相关信息,改变了客户找家政服务的方式,提高了预约家政服务的效率。 本系统是针对网上预约家政服务开发的工作管理系统,包括到所有的工作内容。可以使网上预约家政服务的工作合理化和流程化。本系统包括手机端设计和电脑端设计,有界面和数据库。本系统的使用角色分为管理员和客户、员工三个身份。管理员可以管理系统里的所有信息。员工可以发布服务信息和查询客户的需求进行接单。客户可以发布需求和预约家政服务以及管理预约信息、接单信息。 本功能可以实现家政服务信息的查询和删除,管理员添加家政服务信息功能填写正确的信息就可以实现家政服务信息的添加,点击家政服务信息管理功能可以看到基于微信小程序的家政服务预约系统里所有家政服务的信息,在添加家政服务信息的界面里需要填写标题信息,当信息填写不正确就会造成家政服务信息添加失败。员工风采信息可以使客户更好的了解员工。员工风采信息管理的流程为,管理员点击员工风采信息管理功能,查看员工风采信息,点击员工风采信息添加功能,输入员工风采信息然后点击提交按钮就可以完成员工风采信息的添加。客户需求信息关系着客户的家政服务预约,管理员可以查询和修改客户需求信息,还可以查看客户需求的添加时间。接单信息属于本系统里的核心数据,管理员可以对接单的信息进行查询。本功能设计的目的可以使家政服务进行及时的安排。管理员可以查询员工信息,可以进行修改删除。 客户可以查看自己的预约和修改自己的资料并发布需求以及管理接单信息等。 在首页里可以看到管理员添加和管理的信息,客户可以在首页里进行家政服务的预约和公司介绍信息的了解。 员工可以查询客户需求进行接单以及管理家政服务信息和留言信息、收藏信息等。
数字社区解决方案是一套综合性的系统,旨在通过新基建实现社区的数字化型,打通智慧城市建设的"最后一公里"。该方案以国家政策为背景,响应了国务院、公安部和中央政法会议的号召,强调了社会治安防控体系的建设以及社区治理创新的重要性。 该方案的建设标准由中央综治办牵头,采用"9+X"模式,通过信息采集、案(事)件流等手段,实现五级信息中心的互联互通,提升综治工作的可预见性、精确性和高效性。然而,当前社区面临信息化管理手段不足、安全隐患、人员动向难以掌握和数据资源融合难等问题。 为了解决这些问题,数字社区建设目标提出了"通-治-服"的治理理念,通过街道社区、区政府、公安部门和居民的共同努力,实现社区的平安、幸福和便捷。建设思路围绕"3+N"模式,即人工智能、物联网和数据资源,结合态势感知、业务分析和指挥调度,构建起一个全面的数据支持系统。 数字社区的治理体系通过"一张图"实现社区内各维度的综合态势可视化,"一套表"进行业务分析,"一张网"完成指挥调度。这些工具共同提升了社区治理的智能化和效率。同时,数字社区还提供了包括智慧通行、智慧环保、居家养老和便民服务等在内的多样化数字服务,旨在提升居民的生活质量。 在硬件方面,数字社区拥有IOT物联网边缘网关盒子和AI边缘分析盒子,这些设备能够快速集成老旧小区的物联设备,实现传统摄像设备的智能化改造。平台优势体现在数字化能力中台和多样化的应用,支持云、边、端的协同工作,实现模块化集成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值