- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我带着另一个类似的问题回来了。我目前正在开发一个 Java 程序,该程序将检查图形是否为 2-colorable,即它是否不包含奇数循环(奇数长度的循环)。整个算法应该在 O(V+E) 时间内运行(V 是图中的所有顶点,E 是图中的所有边)。我目前的算法进行深度优先搜索,记录它所走路径中的所有顶点,然后寻找后边,然后记录该边在哪些顶点之间。接下来它从后边缘的一端追踪一条路径,直到它碰到边缘另一端的另一个顶点,从而重新追踪后边缘完成的循环。
我的印象是,对于我图中存在的所有循环,这种遍历可以在 O(V+E) 时间内完成,但我一定遗漏了一些东西,因为我的算法运行时间长得离谱对于非常大的图(10k 个节点,不知道有多少条边)。
我的算法完全错误吗?如果是这样,谁能指出我正确的方向,以便更好地记录这些循环或者可能判断它们是否有奇数个顶点?感谢你们提供的所有帮助。如果您需要,代码如下。
补充:抱歉我忘了,如果图形不是 2-colorable,我需要提供一个奇数循环来证明它不是。
package algorithms311;
import java.util.*;
import java.io.*;
public class CS311 {
public static LinkedList[] DFSIter(Vertex[] v) {
LinkedList[] VOandBE = new LinkedList[2];
VOandBE[0] = new LinkedList();
VOandBE[1] = new LinkedList();
Stack stack = new Stack();
stack.push(v[0]);
v[0].setColor("gray");
while(!stack.empty()) {
Vertex u = (Vertex) stack.peek();
LinkedList adjList = u.getAdjList();
VOandBE[0].add(u.getId());
boolean allVisited = true;
for(int i = 0; i < adjList.size(); i++) {
if(v[(Integer)adjList.get(i)].getColor().equals("white")) {
allVisited = false;
break;
}
else if(v[(Integer)adjList.get(i)].getColor().equals("gray") && u.getPrev() != (Integer)adjList.get(i)) {
int[] edge = new int[2]; //pair of vertices
edge[0] = u.getId(); //from u
edge[1] = (Integer)adjList.get(i); //to v
VOandBE[1].add(edge);
}
}
if(allVisited) {
u.setColor("black");
stack.pop();
}
else {
for(int i = 0; i < adjList.size(); i++) {
if(v[(Integer)adjList.get(i)].getColor().equals("white")) {
stack.push(v[(Integer)adjList.get(i)]);
v[(Integer)adjList.get(i)].setColor("gray");
v[(Integer)adjList.get(i)].setPrev(u.getId());
break;
}
}
}
}
return VOandBE;
}
public static void checkForTwoColor(String g) { //input is a graph formatted as assigned
String graph = g;
try {
// --Read First Line of Input File
// --Find Number of Vertices
FileReader file1 = new FileReader("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph);
BufferedReader bReaderNumEdges = new BufferedReader(file1);
String numVertS = bReaderNumEdges.readLine();
int numVert = Integer.parseInt(numVertS);
System.out.println(numVert + " vertices");
// --Make Vertices
Vertex vertex[] = new Vertex[numVert];
for(int k = 0; k <= numVert - 1; k++) {
vertex[k] = new Vertex(k);
}
// --Adj Lists
FileReader file2 = new FileReader("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph);
BufferedReader bReaderEdges = new BufferedReader(file2);
bReaderEdges.readLine(); //skip first line, that's how many vertices there are
String edge;
while((edge = bReaderEdges.readLine()) != null) {
StringTokenizer ST = new StringTokenizer(edge);
int vArr[] = new int[2];
for(int j = 0; ST.hasMoreTokens(); j++) {
vArr[j] = Integer.parseInt(ST.nextToken());
}
vertex[vArr[0]-1].addAdj(vArr[1]-1);
vertex[vArr[1]-1].addAdj(vArr[0]-1);
}
LinkedList[] l = new LinkedList[2];
l = DFSIter(vertex);//DFS(vertex);
System.out.println(l[0]);
for(int i = 0; i < l[1].size(); i++) {
int[] j = (int[])l[1].get(i);
System.out.print(" [" + j[0] + ", " + j[1] + "] ");
}
LinkedList oddCycle = new LinkedList();
boolean is2Colorable = true;
//System.out.println("iterate through list of back edges");
for(int i = 0; i < l[1].size(); i++) { //iterate through the list of back edges
//System.out.println(i);
int[] q = (int[])(l[1].get(i)); // q = pair of vertices that make up a back edge
int u = q[0]; // edge (u,v)
int v = q[1];
LinkedList cycle = new LinkedList();
if(l[0].indexOf(u) < l[0].indexOf(v)) { //check if u is before v
for(int z = l[0].indexOf(u); z <= l[0].indexOf(v); z++) { //if it is, look for u first; from u to v
cycle.add(l[0].get(z));
}
}
else if(l[0].indexOf(v) < l[0].indexOf(u)) {
for(int z = l[0].indexOf(v); z <= l[0].indexOf(u); z++) { //if it is, look for u first; from u to v
cycle.add(l[0].get(z));
}
}
if((cycle.size() & 1) != 0) { //if it has an odd cycle, print out the cyclic nodes or write them to a file
is2Colorable = false;
oddCycle = cycle;
break;
}
}
if(!is2Colorable) {
System.out.println("Graph is not 2-colorable, odd cycle exists");
if(oddCycle.size() <= 50) {
System.out.println(oddCycle);
}
else {
try {
BufferedWriter outFile = new BufferedWriter(new FileWriter("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph + "OddCycle.txt"));
String cyc = oddCycle.toString();
outFile.write(cyc);
outFile.close();
}
catch (IOException e) {
System.out.println("Could not write file");
}
}
}
}
catch (IOException e) {
System.out.println("Could not open file");
}
System.out.println("Done!");
}
public static void main(String[] args) {
//checkForTwoColor("smallgraph1");
//checkForTwoColor("smallgraph2");
//checkForTwoColor("smallgraph3");
//checkForTwoColor("smallgraph4");
checkForTwoColor("smallgraph5");
//checkForTwoColor("largegraph1");
}
}
顶点类
package algorithms311;
import java.util.*;
public class Vertex implements Comparable {
public int id;
public LinkedList adjVert = new LinkedList();
public String color = "white";
public int dTime;
public int fTime;
public int prev;
public boolean visited = false;
public Vertex(int idnum) {
id = idnum;
}
public int getId() {
return id;
}
public int compareTo(Object obj) {
Vertex vert = (Vertex) obj;
return id-vert.getId();
}
@Override public String toString(){
return "Vertex # " + id;
}
public void setColor(String newColor) {
color = newColor;
}
public String getColor() {
return color;
}
public void setDTime(int d) {
dTime = d;
}
public void setFTime(int f) {
fTime = f;
}
public int getDTime() {
return dTime;
}
public int getFTime() {
return fTime;
}
public void setPrev(int v) {
prev = v;
}
public int getPrev() {
return prev;
}
public LinkedList getAdjList() {
return adjVert;
}
public void addAdj(int a) { //adds a vertex id to this vertex's adj list
adjVert.add(a);
}
public void visited() {
visited = true;
}
public boolean wasVisited() {
return visited;
}
}
最佳答案
I was under the impression that this kind of traversing could be done in O(V+E) time for all cycles that exist in my graph
一个图中的循环可能比 O(V+E) 多得多。如果您迭代所有这些,您将运行很长时间。
回到你最初的想法,你可以尝试实现一个简单的算法来用两种颜色给图形着色(将任意节点标记为黑色,所有邻居标记为白色,所有邻居标记为黑色,等等;这将是一个广度- 第一次搜索)。这确实是在 O(V+E) 时间内完成的。如果你成功了,那么图形是 2-colorable 的。如果你失败了,那不是。
编辑:如果您需要一个循环来证明图形不是 2-colorable,只需为每个节点记录您从中遍历到它的顶点。当您碰巧从黑色顶点 A 遍历到黑色顶点 B(因此需要将黑色 B 着色为白色并证明您的图形不是 2-colorable)时,您通过回头查看父节点得到循环:
X -> Y -> Z -> U -> V -> P -> Q -> A
\-> D -> E -> B
然后,A-B-E-D-V-P-Q
(到它们共同祖先的路径)就是您需要的循环。
请注意,在这个版本中,您不必检查所有 个循环,您只需输出第一个循环,其中树的后边具有相同颜色的两个顶点。
关于java - 检查无向图中的奇环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1838934/
我需要根据需要动态设置文本区域,但它不想正常工作。 JQuery 会自行检查,但无法检查是否已检查。但是当您在第二个单选框内单击时,始终需要文本区域。我尝试了很多次让它工作,但它仍然有问题。我添加了“
我需要在 Django 中进行 API 调用(某种形式),作为我们所需的自定义身份验证系统的一部分。用户名和密码通过 SSL 发送到特定 URL(对这些参数使用 GET),响应应该是 HTTP 200
我将在我的可移植 C 代码中使用 #warning 来生成编译时警告。但并非所有平台都支持 #warning。有什么方法可以找到该平台是否支持 #warning。 #ifdef warning
我编写了一个函数来检查某个数字是否存在于某个区间内。停止搜索的最佳方法是什么?这个: for (i = a; i <= b; i++) { fi = f(i); if (fi == c) {
我想知道在 c 中是否有一种方法可以检查,例如在 for 函数中,如果变量等于或不等于某些字符,而不必每次都重复进行相等性检查。如果我没记错的话,以这种方式检查相等性是不正确的: if (a == (
我有如下日志功能 void log_error(char * file_name, int line_num, int err_code) { printf("%s:%d:%s\n", fil
使用 ssh-keygen 生成的 key 对在 macOS 上可以有不同的格式。 macOS 可读的标准 PEM ASN.1 对象 SecKey API 带有文本标题的 PEM OpenSSH ke
我正在尝试编写一个 excel if 语句。我不熟悉使用 Excel 具有的所有额外功能。我正在使用一个名为 importXML() 的函数.我正在尝试检查我正在使用的函数是否生成“#VALUE!”错
有没有办法检查是否没有 AIO 写入给定文件?我在我的 Unix 类(class)上制作了一个项目,该项目将是一个上下文无关(基于 UDP)的国际象棋服务器,并且所有数据都必须存储在文件中。应用程序将
我有一个如下所示的函数: public Status execute() { Status status = doSomething(); if (status != Stat
我正在使用 Composer,我不希望 PhpStorm 在 vendor 文件夹上运行任何错误检查或检查,因为它对 vendor/中的某些代码显示误报composer/autoload_static
Chapel 的一个很好的特性是它区分了数组的域和它的分布。检查两个数组是否具有相同的域和分布(通常想要的)的最佳方法是什么? 我能看到的最好的方法是检查 D1==D2和 D1.dist==D2.di
在我的 JavaScript 函数中,我为所有输入、文本区域和选择字段提供实际值作为 initial_value: $('input, textarea, select').each(function
我正在编写一个分解为几个简单函数的 PHP 类。在构造函数中,它调用另一个名为 processFile 的函数。该函数调用 5 个私有(private)函数并进行检查。如果检查失败,它会将消息分配给
这个问题已经有答案了: How to detect if user it trying to open a link in a new tab? (2 个回答) 已关闭 7 年前。 我认为 JavaS
我正在浏览我们的代码库并看到很多这样的测试: declare @row_id int = ... declare @row_attribute string select @row_attribu
我正在声明一个用作比较的函数。我的问题是: 为什么条件充当语句? 为什么第 4 行可以工作,而第 5 行却不行? 我知道这段代码不切实际且未使用,但为什么编译器允许这种语法? 谷歌没有找到答案。但话又
到目前为止,我有一个带有空文本字段的 PHP Kontaktform,并使用以下命令检查了所需的字段: $name = check_input($_POST['name'], "请输入姓名。"); 现
目前,我能想到的合理检查的唯一方法没有臃肿的逻辑: if ( $value > 0 ) { // Okay } else { // Not Okay } 有没有更好的办法? 最佳答案
我正在尝试运行一个脚本,如果 i 存在(意味着存在 i 值,任何值)或其他部分,我希望运行其中的一部分如果i没有值就运行,有人可以启发我吗? 我说的是 for 循环,比如 for (var i=0;
我是一名优秀的程序员,十分优秀!