2-SAT相关

什么是2-SAT?

       其实2-SAT,就是有很多组人,每组有只有两个成员,要你从每组中选一个人。其中,有一些人有矛盾不能同时选。如果抽象的说,就是有n个集合,每个集合有两个元素,从每个集合中选出一个元素,其中有一些元素不能同时选。判定是否有一种方案可以满足上列的条件。

2-SAT的主要问题?

  是否有解,如果有解给出一组可行解,有时有要求字典序最小的解。

主要算法

  对这类问题进行构造建图。下面进行一些约定:我们把假定有i 组人,第i组的两个成员分别为Ai 和 Ai'。如果要选Ai就必须选Aj,那么就把 Ai  指向 Aj。如果Ai和Aj有矛盾,则选Ai 就必须选Aj',选Aj 就必须选Ai'。特别的,如果Ai 和 Ai'中,一定不选Ai,就连一条由Ai指向Ai'的边。2-SAT问题可以转为求有向图的强连通分量和拓扑排序(具体见 由对称性解2-SAT问题)。

下面是算法的步骤:

    1、根据题意建图
    2、求强连通分量( 这有一篇大神写的强连通分量的文章)
    3、拓扑求可行解

算法的模板:

如果有n组人,有m条边那么下面算法的效率为O(m)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//如果不求方案数就要把下面这句删掉
#define REQUE_COLOR 1

//writen by nothi

#ifdef  REQUE_COLOR
const int RED = 1;
const int BULE = 2;
const int WHITE = 0;
#endif

const int maxn = 1100;
//顶点的个数,这里的顶点个数实际上就是组的个数
//组的编号从0到n-1
const int maxn2 = maxn*2;
const int maxm = maxn*maxn;//边的条数

typedef struct Edge{
	int s;
	int e;
	int next;
}Edge;

typedef struct Adj{
	int edge_sum;
	int head[maxn2];
	Edge edge[maxm];

	void initial(){	
		edge_sum = 0;
		memset(head,-1,sizeof(head));
	}

	void add_edge(int a, int b){
		edge[edge_sum].s = a;
		edge[edge_sum].e = b;
		edge[edge_sum].next = head[a];
		head[a] = edge_sum++; 
	} 
}Adj;

#ifdef  REQUE_COLOR
Adj op_adj;
#endif

//顶点序号(组的编号)从0到n-1
//编号为i的组,在实际的算法中组员是2*i 和 2*i+1
//所以对于组员i,和它同组的另一个组员为i^1
//color[belong[u]] == RED 是解
//选调用initial()初始化,再用solve()解决问题
//如果要求一组可行解,调用creat();
typedef struct Two_sat{
	int n;//n是顶点数

	Adj *adj;
	Edge *e;
	int *head;
	int top, cnt, cur;
	int dfn[maxn2];
	int low[maxn2];
	int stack[maxn2];
	int belong[maxn2];	
	int instack[maxn2];

	void initial(Adj* _adj,int _n){
		n = _n;
		adj = _adj;
		e = (*adj).edge;
		head = (*adj).head;
	}

	bool check(){	
		int i, j;
		tarjan();
		for(i = 0; i < 2*n; i += 2)
			if(belong[i] == belong[i^1])
				return false;
		return true;
	}

	int min(int a, int b){
		if(a < b) return a;
		else return b;
	}

	void tarjan(int i){
		int j = head[i];

		dfn[i] = low[i] = ++cur;

		instack[i] = 1;
		stack[top++] = i;

		while(j != -1){
			int u = e[j].e;
			if       (dfn[u] == -1){
				tarjan(u);
				low[i] = min(low[i],low[u]);
			}else if (instack[u])
				low[i] = min(low[i],dfn[u]);
			j = e[j].next; 
		}

		if(dfn[i] == low[i]){
			++cnt;		
			do{
				j = stack[--top];
				instack[j] = 0;
				belong[j] = cnt;
			}while(j != i);
		}
	}

	void tarjan(){
		int i, j;
		cur = cnt = top = 0;
		memset(dfn,-1,sizeof(dfn));
		for(i = 0; i < 2*n; i++)	
			if(dfn[i] == -1)
				tarjan(i);
	}
		
       #ifdef REQUE_COLOR
       //求具体的方案
       int opp[maxn2];
       int color[maxn2];
       int indegree[maxn2];
       
       void creat(){
	       int u, v, i, j;
	       memset(indegree,0,sizeof(indegree));
	       op_adj.initial();

	       for(i = 0; i < 2*n; i += 2){
		       opp[belong[i]] = belong[i^1];
		       opp[belong[i^1]] = belong[i];
	       }

	       for(i = 0; i < (*adj).edge_sum; i++){
			u = belong[e[i].s];
			v = belong[e[i].e];
			if(u == v) continue;
			++indegree[u];
			op_adj.add_edge(v,u);
	       }

	       toposort();
       }

       void toposort(){ 
	       int *head1 = op_adj.head;
	       Edge *edge = op_adj.edge;
	       int i, j, p, now, head, tail,next;

	       head = tail = 0;
	       memset(color,WHITE,sizeof(color));
	       for(i = 1; i <= cnt; i++)
		       if(!indegree[i])
				stack[++head] = i;

	      	while(head != tail){ 
			now = stack[++tail];
			if(color[now] != WHITE)	continue;

		        color[now] = RED;
			color[opp[now]] = BULE;

			p = head1[now];
			while(p != -1){
				next =edge[p].e;	
				--indegree[next];
				if(indegree[next] == 0){
					stack[++head] = next;
				}
				p = edge[p].next;
			}
		}
       }
       #endif
}Two_sat;

Adj adj;
Two_sat ts;




相关问题:

直接的判定问题:
   hdu-1824
         hdu-3602
         hdu-4115
         poj-3678
       
二分答案+2-SAT:
        hdu-1815
        hdu-1816
        hdu-3622
        hdu-3715
        poj-2296
        poj-3207
       
求一组可行解:
        poj-3648
        poj-3683
        poj-3905

求字典序最小的方案:
       hdu-1814
      这题可以看  这里


 转载请注明出处--nothi

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置和动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性和优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识和Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据和技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
先看效果: https://pan.quark.cn/s/3756295eddc9 在C#软件开发过程中,DateTimePicker组件被视为一种常见且关键的构成部分,它为用户提供了图形化的途径来选取日期与时间。 此类控件多应用于需要用户输入日期或时间数据的场景,例如日程管理、订单管理或时间记录等情境。 针对这一主题,我们将细致研究DateTimePicker的操作方法、具备的功能以及相关的C#编程理念。 DateTimePicker控件是由.NET Framework所支持的一种界面组件,适用于在Windows Forms应用程序中部署。 在构建阶段,程序员能够通过调整属性来设定其视觉形态及运作模式,诸如设定日期的显示格式、是否展现时间选项、预设的初始值等。 在执行阶段,用户能够通过点击日历图标的下拉列表来选定日期,或是在文本区域直接键入日期信息,随后按下Tab键或回车键以确认所选定的内容。 在C#语言中,DateTime结构是处理日期与时间数据的核心,而DateTimePicker控件的值则表现为DateTime类型的实例。 用户能够借助`Value`属性来读取或设定用户所选择的日期与时间。 例如,以下代码片段展示了如何为DateTimePicker设定初始的日期值:```csharpDateTimePicker dateTimePicker = new DateTimePicker();dateTimePicker.Value = DateTime.Now;```再者,DateTimePicker控件还内置了事件响应机制,比如`ValueChanged`事件,当用户修改日期或时间时会自动激活。 开发者可以注册该事件以执行特定的功能,例如进行输入验证或更新关联的数据:``...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值