ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

图论杂算法选讲

2022-07-15 09:31:44  阅读:155  来源: 互联网

标签:10 图论 texttt 选讲 SPFA leq 算法 add dis


差分约束

例题:P5960 【模板】差分约束算法

给出一组包含 \(m\) 个不等式,有 \(n\) 个未知数的形如:

\[\begin{cases} x_{c_1}-x_{c'_1}\leq y_1 \\x_{c_2}-x_{c'_2} \leq y_2 \\ \cdots\\ x_{c_m} - x_{c'_m}\leq y_m\end{cases} \]

的不等式组,求任意一组满足这个不等式组的解。

对于 \(100\%\) 的数据,\(1\leq n,m \leq 5\times 10^3\),\(-10^4\leq y\leq 10^4\),\(1\leq c,c'\leq n\),\(c \neq c'\)。

对于这种解不等式问题,我们可以使用差分约束算算法。

首先,先建立一个超级源点 \(0\),然后对于 \(a - b\leq c\),连边 \((b,a,c)\),最后跑最短路即可,无解就是存在负环。

这一步可以用SPFA,Dijkstra不行。

时间复杂度 \(O(nm)\)。

伪代码如下:

Input n,m;
For i in Range(1,n){
	add_edge(0,i,0);
}
For i in Range(1,m){
	Input from,to,weight;
	add_edge(from,to,weight);
}
res=Spfa(start=0);
If(res is not){
	Print "NO";
}
Else{
	For i in Range(1,n){
		Print Dis[i];
		Putchar ' ';
	}
}
end

P1993 小 K 的农场

小 K 在 \(\texttt{Minecraft}\) 里面建立很多很多的农场,总共 \(n\) 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 \(m\) 个),以下列三种形式描述:

  • 农场 \(a\) 比农场 \(b\) 至少多种植了 \(c\) 个单位的作物;
  • 农场 \(a\) 比农场 \(b\) 至多多种植了 \(c\) 个单位的作物;
  • 农场 \(a\) 与农场 \(b\) 种植的作物数一样多。

但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

对于 \(100\%\) 的数据,保证 \(1 \le n,m,a,b,c \le 5 \times 10^3\)。

对于形式 \(1\),即 \(b-a\leq -c\),连边 \((a,b,-c)\)。

对于形式 \(2\),即 \(a-b\leq c\),连边 \((b,a,c)\)。

对于形式 \(3\),即 \(a-b \leq 0\) 和 \(b-a\leq 0\),连边 \((a,b,0)\) 与 \((b,a,0)\)。

然后跑差分约束即可。

Johnson 全源最短路 | P5905 【模板】Johnson 全源最短路

给定一个包含 \(n\) 个结点和 \(m\) 条带权边的有向图,求所有点对间的最短路径长度,一条路径的长度定义为这条路径上所有边的权值和。

注意:

  1. 边权可能为负,且图中可能存在重边和自环;
  2. 部分数据卡 \(n\) 轮 SPFA 算法。

若图中存在负环,输出仅一行 \(-1\)。

若图中不存在负环:

输出 \(n\) 行:令 \(dis_{i,j}\) 为从 \(i\) 到 \(j\) 的最短路,在第 \(i\) 行输出 \(\sum\limits_{j=1}^n j\times dis_{i,j}\),注意这个结果可能超过 int 存储范围。

如果不存在从 \(i\) 到 \(j\) 的路径,则 \(dis_{i,j}=10^9\);如果 \(i=j\),则 \(dis_{i,j}=0\)。

对于 \(100\%\) 的数据,\(1\leq n\leq 3\times 10^3,\ \ 1\leq m\leq 6\times 10^3,\ \ 1\leq u,v\leq n,\ \ -3\times 10^5\leq w\leq 3\times 10^5\)。

注意给出的图不一定连通。

这道题卡 \(\texttt{Floyd, Dijkstra, SPFA}\) 等算法,但是不卡 \(\texttt{Johnson}\)。

\(\texttt{Johnson}\),就是将 \(\texttt{SPFA}\) 与 \(\texttt{Dijkstra}\) 结合,具体操作如下:

先建立超级源 \(0\) ,然后跑 \(\texttt{SPFA}\),令 \(h_i\) 为 \(0 \to i\) 的最短路径,将原来的边 \((u,v,w)\) 设为 \((u,v,w+h_u-h_j)\),然后跑 \(n\) 遍 \(\texttt{Dijkstra}\) 即可,因为 \(w+h_u-h_j\geq 0\),最后记得还原路径边权。

时间复杂度 \(O(nm\log m)\)(\(\texttt{Dijkstra}\) 开启了堆优化)

伪代码如下:

Input n,m
For i in Range(1,m){
	Input u,v,w
	AddEdge(u,v,w)
}
For i in Range(1,n){
	AddEdge(0,i,0)
}
If(not SPFA::SPFA(start=0)){
	Print -1
	Exit
}
For i in Range(1,n){
	For j in ConnectedEdges(i){
		g[j].weight += (SPFA::dis[i]-SPFA::dis[g[j].to])
	}
}
For i in Range(1,n){
    int ans=0
    heap_dijkstra(start=i)
    For j in Range(1,n){
        If(dis[j]==1e9){
            ans+=j*1e9
        }
        Else{
            ans+=j*(dis[j]+SPFA::dis[j]-SPFA::dis[i])
        }
    }
    Print ans
    Putchar '\n'
}

2-SAT问题

P4782 【模板】2-SAT 问题

有 \(n\) 个布尔变量 \(x_1\)\(\sim\)\(x_n\),另有 \(m\) 个需要满足的条件,每个条件的形式都是 「\(x_i\) 为 true / false 或 \(x_j\) 为 true / false」。比如 「\(x_1\) 为真或 \(x_3\) 为假」、「\(x_7\) 为假或 \(x_2\) 为假」。

2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

如无解,输出 IMPOSSIBLE;否则输出 POSSIBLE

下一行 \(n\) 个整数 \(x_1\sim x_n\)(\(x_i\in\{0,1\}\)),表示构造出的解。

\(1\leq n, m\leq 10^6\) , 前 \(3\) 个点卡小错误,后面 \(5\) 个点卡效率,数据随机生成。

  • 对于 \(x_i = \operatorname{true},x_j=\operatorname{true}\),连边 \((i^{'},j)\) 与 \((j^{'},i)\)。
  • 对于 \(x_i = \operatorname{false},x_j=\operatorname{true}\),连边 \((i,j)\) 与 \((j^{'},i^{'})\)。
  • 对于 \(x_i = \operatorname{true},x_j=\operatorname{false}\),连边 \((i^{'},j^{'})\) 与 \((j,i)\)。
  • 对于 \(x_i = \operatorname{false},x_j=\operatorname{false}\),连边 \((i,j^{'})\) 与 \((j,i^{'})\)。

然后跑 \(\texttt{Tarjan}\) 强连通分量,如果 \(i\) 与 \(i^{'}\) 在同一个强连通分量,那么存在悖论,输出 \(\texttt{IMPOSSIBLE}\),否则输出 \(\texttt{POSSIBLE}\)。

最后输出答案,对于 \(\operatorname{SCC\_ID}(i) \lt \operatorname{SCC\_ID}(i^{'})\),输出 \(1\) 否则输出 \(0\)。

这次不放伪代码了,直接放C++程序片段吧。

int main(){
	cin>>n>>m;
	for(int i=0;i<m;i++){
		int i_,a,j,b;
		cin>>i_>>a>>j>>b;
		if(a&&b){
			add(i_+n,j,114);
			add(j+n,i_,514);
		}
		if(!a&&b){
			add(i_,j,114);
			add(j+n,i_+n,514);
		}
		if(a&&!b){
			add(i_+n,j+n,114);
			add(j,i_,514);
		}
		if(!a&&!b){
			add(i_,j+n,114);
			add(j,i_+n,514);
		}
	}	
	for(int i=1;i<=(n<<1);i++){
		if(!dfsed[i]){
			tarjan(i);
		}
	}
	for(int i=1;i<=n;i++){
		if(c[i]==c[i+n]){
			cout<<"IMPOSSIBLE";
			return 0;
		}
	}
	cout<<"POSSIBLE"<<'\n';
	for(int i=1;i<=n;i++){
		cout<<((c[i]<c[i+n])?1:0)<<' ';
	}
	return 0;
} 

标签:10,图论,texttt,选讲,SPFA,leq,算法,add,dis
来源: https://www.cnblogs.com/zheyuanxie/p/graph-theory-algorithms.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有