笔记:前缀优化建图

建图时, \(N^2\) 的算法有时让人难以接受,时间空间过大,为解决这个问题必须优化点集内建边算法.

这是我们原来的建图方式,朴素但是有效好歹92分

如何优化呢?关键就在于缩小 \(N^2\) 的计算量,而要完成这一步,关键是减少建边的数量(或者说优化建边的方式)

\(2-SAT\) 里变量两种状态的点是关键,不可能直接在这 \(2N\) 个点之上优化。自然而然得,我们应当新建若干点作为媒介使新图拥有原来的性质,而这 \(2N\) 个点的地位等价(感觉一下?),自然应当新建 \(2N\)个点一一对应(连边)

为保持原来点的性质不变,出点继续出,入点继续入

然后自然而然得,我们可以转移边

对于这幅图,我们容易发现,\(9-16\)\(10-16\)\(11-16\) 这三条边可以变成\(9-10\)\(10-11\)\(11-16\)这样的三条边,而同时 \(9-10\) 还可以用于\(9-15\)\(10-15\)\(9-10\)\(10-15\)的转换。所以经过这样的转化,我们能得到这张图

但是这张图存在致命的错误:出现了 \(1-9-14-13-2\)\(1-9-10-13-2\) 之类的错误线路,为了调整这种线路,我们将 \(9-14\) 调整为 \(9-4\)\(10-13\) 调整为 \(3-13\)(保持 \(9-10\)\(14-13\) 之类的由有利边仍然存在),类似操作后,有了这张图

此时图形已经符合原图的所有性质,但是为了便于进行循环操作,我们对其微调(也就\(4\)条边),得到这张图(也就是程序得到的图)

附上点集内代码,可以结合图片食用

for(int i=1;i<=t;i++)
{
	ac[i]=read();
	add(ac[i]+n,ac[i]+3*n);
	add(ac[i]+2*n,ac[i]);
}
for(int i=2;i<=t;i++)
{
	add(ac[i-1]+3*n,ac[i]+3*n);
	add(ac[i]+2*n,ac[i-1]+2*n);
	add(ac[i-1]+3*n,ac[i]);
	add(ac[i]+n,ac[i-1]+2*n);
}

例题:P6378 [PA2010]Riddle

本文摘自:阴阳八卦 的博客

posted @ 2020-12-01 22:31  -lala-  阅读(516)  评论(1编辑  收藏  举报