0
点赞
收藏
分享

微信扫一扫

写一个图的算法(一)


写一个图的算法(一)

删除图中的节点

删除6结点

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class DeleteNode{
/* static List<LinkedList<Integer>> templist; */
static List<LinkedList<Integer>> totallist;
static List<LinkedList<Integer>> Normallist;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

int N = sc.nextInt();
int M = sc.nextInt();
totallist = new ArrayList<LinkedList<Integer>>();
Normallist = new ArrayList<LinkedList<Integer>>();
for(int i=0;i<N;i++) {
totallist.add(new LinkedList<Integer>());
Normallist.add(new LinkedList<Integer>());
}
for(int i=0;i<M;i++) {
int s = sc.nextInt();
int e = sc.nextInt();
/* if(hasEdge(s-1,e-1))continue; */
totallist.get(s-1).add(e-1);
totallist.get(e-1).add(s-1);
Normallist.get(s-1).add(e-1);
Normallist.get(e-1).add(s-1);
}
System.out.println(" ");
List<LinkedList<Integer>> deleteNode = deleteNode(6);
System.out.println(" ");
}

private static boolean hasEdge(int i, int j) { // TODO Auto-generated method
for(Integer m:totallist.get(i)) { if(m==j) return true; } return false;
}



private static List<LinkedList<Integer>> deleteNode(int i) {
List<LinkedList<Integer>> templist = new ArrayList<LinkedList<Integer>>(totallist);
templist.remove(i);
templist.add(i,new LinkedList<Integer>());

for(int j=0;j<templist.size();j++) {
LinkedList<Integer> temp = templist.get(j);
Iterator<Integer> it = temp.iterator();
while(it.hasNext()) {
Integer intNum = it.next();
if(i==intNum.intValue()) { //引用变量Integer超出255范围后==比较为false,拆箱
it.remove(); //迭代器进行删除
}
}
}
totallist.clear();
totallist.addAll(Normallist);
return templist;

//去除集合中的重复元素
/* templist.remove(i); */
/* for(LinkedList item:templist) {
HashSet<Integer> hashSet = new HashSet<>(item);
item.clear();
item.addAll(hashSet);
}*/
}
}

测试用例:

10 8
1 5
3 9
9 7
7 4
6 7
10 5
10 2
8 5

输出:

写一个图的算法(一)_写一个图的算法(一)

写一个图的算法(一)_java_02

 

并查集算法

 并查集判断两点是否相连与路径压缩

并查集常用来解决连通性的问题,即将一个图中连通的部分划分出来。当我们判断图中两个点之间是否存在路径时,就可以根据判断他们是否在一个连通区域。

并查集的思想就是,同一个连通区域内的所有点的根节点是同一个。将每个点映射成一个数字。先假设每个点的根节点就是他们自己,然后我们以此输入连通的点对,然后将其中一个点的根节点赋成另一个节点的根节点,这样这两个点所在连通区域又相互连通了。 并查集的主要操作有:

  • find(int m):这是并查集的基本操作,查找m的根节点。
  • isConnected(int m,int n):判断m,n两个点是否在一个连通区域。
  • union(int m,int n):合并m,n两个点所在的连通区域。

class UnionFind {
int[] parents;

public UnionFind(int totalNodes) {
parents = new int[totalNodes];
for (int i = 0; i < totalNodes; i++) {
parents[i] = i;
}
}
// 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内.
void union(int node1, int node2) {
int root1 = find(node1);
int root2 = find(node2);
if (root1 != root2) {
parents[root2] = root1;
}
}

int find(int node) {
while (parents[node] != node) {
// 当前节点的父节点 指向父节点的父节点.
// 保证一个连通区域最终的parents只有一个.
parents[node] = parents[parents[node]];
node = parents[node];
}

return node;
}

boolean isConnected(int node1, int node2) {
return find(node1) == find(node2);
}
}

 

典型案例:

判断没有与0相连结点的个数

写一个图的算法(一)_List_03

测试用例:

8 7 
0 1
3 0
1 2
3 7
8 6
2 5
7 2

并查集实现

public class UF {
static int[] parents;
static int[] ranks;//基于高度的优化
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int M = scanner.nextInt();
parents = new int[N+1];
ranks = new int[N+1];
for(int i = 0;i<N+1;i++) {
parents[i] = i;
ranks[i] = 1;
}
for(int i=0;i<M;i++){
int s = scanner.nextInt();
int e = scanner.nextInt();
unionElement(s,e);
}
int count = 0;
for(int i =0;i<N+1;i++) {
if(!isConnected(0, i)) {
count++;
}
}
System.out.println(count);
}
private static void unionElement(int s, int e) {
// TODO Auto-generated method stub
int pRoot = find(s);
int qRoot = find(e);
if(pRoot==qRoot) return;
if(ranks[pRoot]<ranks[qRoot]) {
parents[pRoot] = qRoot; //高度小的节点指向高度比较高的节点
}else if(ranks[qRoot]<ranks[pRoot]) {
parents[qRoot] = pRoot;
}else {
parents[qRoot] = pRoot;
ranks[pRoot]+=1;
}
}
private static boolean isConnected(int x,int y) {
return find(x) == find(y);
}

private static int find(int n) {
if(n!=parents[n])
parents[n] = find(parents[n]);//路径压缩
return parents[n];
}
}

输出:

3

经典案例

给定一个二维的矩阵,包含 ​​'X'​​​ 和 ​​'O'​​(字母 O)。

找到所有被 ​​'X'​​​ 围绕的区域,并将这些区域里所有的 ​​'O'​​​ 用 ​​'X'​​ 填充。

示例:

X X X X
X O O X
X X O X
X O X X

运行你的函数后,矩阵变为:

X X X X
X X X X
X X X X
X O X X

解释:

被围绕的区间不会存在于边界上,换句话说,任何边界上的 ​​'O'​​​ 都不会被填充为 ​​'X'​​​。 任何不在边界上,或不与边界上的 ​​'O'​​​ 相连的 ​​'O'​​​ 最终都会被填充为 ​​'X'​​。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

我们的思路是把所有边界上的O看做一个连通区域。遇到O就执行并查集合并操作,这样所有的O就会被分成两类

  • 和边界上的O在一个连通区域内的。这些O我们保留。
  • 不和边界上的O在一个连通区域内的。这些O就是被包围的,替换。

由于并查集我们一般用一维数组来记录,方便查找parants,所以我们将二维坐标用node函数转化为一维坐标。

实现

public class IsandsFind {

static char[][] grid = {
{'x','x','x','x'},
{'x','0','0','x'},
{'x','x','0','x'},
{'x','0','x','x'}
};
static int[] parents;
static int[] ranks;
static int m;
static int n;
public static void main(String[] args) {
m = grid.length;
n = grid[0].length;
parents = new int[m*n+1];
ranks = new int[m*n+1];
int dummyNode = m*n;
for(int i=0;i<m*n+1;i++) {
parents[i] = i;
ranks[i] =1;
}
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
if(grid[i][j]=='0') {
// 遇到O进行并查集操作合并
if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
// 边界上的O,把它和dummyNode 合并成一个连通区域.
unionElement(node(i, j), dummyNode);
} else {
// 和上下左右合并成一个连通区域.
if (i > 0 && grid[i - 1][j] == '0')
unionElement(node(i, j), node(i - 1, j));
if (i < m - 1 && grid[i + 1][j] == '0')
unionElement(node(i, j), node(i + 1, j));
if (j > 0 && grid[i][j - 1] == '0')
unionElement(node(i, j), node(i, j - 1));
if (j < n - 1 && grid[i][j + 1] == '0')
unionElement(node(i, j), node(i, j + 1));
}
}
}
}

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (isConnected(node(i, j), dummyNode)) {
// 和dummyNode 在一个连通区域的,那么就是O;
grid[i][j] = '0';
} else {
grid[i][j] = 'x';
}
}
}
System.out.println(grid);
}

private static int node(int i,int j) {
return i*n+j;
}

private static boolean isConnected(int x,int y) {
return find(x)==find(y);
}

private static int find(int n) {
// TODO Auto-generated method stub
if(n!=parents[n])
parents[n] = find(parents[n]);
return parents[n];
}
private static void unionElement(int s,int e) {
int pRoot = find(s);
int qRoot = find(e);
if(pRoot==qRoot) return;
if(ranks[pRoot]<ranks[qRoot]) {
parents[pRoot] = qRoot;
}else if(ranks[qRoot]<ranks[pRoot]) {
parents[qRoot] = pRoot;
}else {
parents[qRoot] = pRoot;
ranks[pRoot]+=1;
}
}
}

输出:

写一个图的算法(一)_java_04

 

 

图的遍历-深度优先搜索

DFS获取无向图中的所有路径

写一个图的算法(一)_写一个图的算法(一)_05

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

public class Path {
private int[] form;
private int s;
private Graph graph;
private boolean[] visited;
private List<int[]> totalList;


public Path(int s, Graph graph) {
super();
this.s = s;
this.graph = graph;
visited = new boolean[graph.V()];
form = new int[graph.V()];
for(int i=0;i<graph.V();i++) {
form[i] = -1;
}
totalList = new ArrayList<>();
int toIndex = 6;
DFS(s,toIndex);
}

private boolean hasPath(int w) {
return form[w]!=-1;
//return visited[w];
}
private List<List<Integer>> path(int w){
List<List<Integer>> retlist = new ArrayList<>();
for(int[] tempForm:totalList) {
List<Integer> list = new ArrayList<>();
Deque<Integer> deque = new LinkedList<>();
int p = w;
while(p!=-1) {
deque.push(p);
p = tempForm[p];

}
while(!deque.isEmpty()) {
list.add(deque.pop());
}
retlist.add(list);
}
return retlist;

}
//showPath(6)
void showPath(int w) {
assert hasPath(w);
List<List<Integer>> path = path(w);
for(int i=0;i<path.size();i++) {
for(int j=0;j<path.get(i).size();j++) {
System.out.println(path.get(i).get(j));
if(j!=path.get(i).size()-1)
System.out.print(" -> ");
else
System.out.println();
}
}


}

private void DFS(int i,int toIndex) {
// TODO Auto-generated method stub
visited[i] = true;
if(i==toIndex) {
visited[i] = false;
return;
}
for(int item :graph.adj(i)) {
if(!visited[item]) {
form[item] = i;
if(item==toIndex) {
visited[i] = false;
int[] temp = Arrays.copyOf(form, form.length);
totalList.add(temp);
}
DFS(item,toIndex);
//form[item] = i;
/*if(item==toIndex) {
int[] temp = Arrays.copyOf(form, form.length);
totalList.add(temp);
Arrays.fill(form, -1);
}*/
}
}
visited[i] = false;
form[i] = -1;
}
}

打印输出:

写一个图的算法(一)_java_06

DFS获取图的连通分量判断两点是否连接

深度遍历是把与i相连接的,不是相邻近的所有的节点遍历一边,没遍历的节点一定在其他的联通分量中

public class Compents {
Graph graph;
private boolean[] visited;
private int count;
private int[] ids;
public Compents(Graph graph) {
this.graph = graph;
int V = graph.V();
visited = new boolean[V];
ids = new int[V];
count = 0;
for(int i=0;i<V;i++) {
ids[i] = -1;
}
//connect numbers
for(int i=0;i<V;i++) {
if(!visited[i]) {
DFS(i);
count++;
}
}
}
private void DFS(int i) {
// TODO Auto-generated method stub
visited[i] = true;
ids[i] = count;
for(int item :graph.adj(i)) {
if(!visited[item])
DFS(item);
}

}

int count() {
return count;
}

boolean isConnected(int v,int w) {
return ids[v] == ids[w];
}


}

DFS遍历有向无环有权图任意两点间最优路径

写一个图的算法(一)_List_07

DFS(0,7); 计算0-7所有路径中权值最小的

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;


/**
* 13:22:38 13:26:13 13:47:39 14:52:02 13:53:51 13:55:37 14:56:52
* 13:57:55 14:01:08 14:02:55 14:08:10 14:11;35 14:16:18 14:17:44
* 14:19:04 14:22:58 14:25:29
* @author Administrator
*
*/
public class weighDirRoute {
static List<List<int[]>> totallist;
static boolean[] visited;
static int MaxCount;
static List<Integer> compareMax;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int M = scanner.nextInt();
totallist = new ArrayList<>();
compareMax= new ArrayList<>();
visited = new boolean[N];
for(int i=0;i<N;i++) {
totallist.add(new LinkedList<>());
}
for(int i=0;i<M;i++) {
int s = scanner.nextInt();
int e = scanner.nextInt();
int w = scanner.nextInt();
totallist.get(s).add(new int[]{s,e,w});
}

MaxCount = 0;
DFS(0,7);
Integer answer = Collections.min(compareMax);
System.out.println(answer);
}
private static void DFS(int i,int toIndex) {
// TODO Auto-generated method stub
visited[i] = true;
for(int[] items:totallist.get(i)) {
int item = items[1];
int Count = items[2];
if(!visited[item]) {
MaxCount+=Count;
if(item==toIndex) {
compareMax.add(MaxCount);
}
DFS(item,toIndex);
/*if(item==toIndex) {
compareMax.add(MaxCount);
}*/
MaxCount-=Count;
}
}
visited[i] = false;
}
}

写一个图的算法(一)_java_08

输出:

写一个图的算法(一)_i++_09

DFS计算节点间能到达的最远距离

无向图

写一个图的算法(一)_i++_10

写一个图的算法(一)_List_11

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
/**
* @author Administrator
* 6:52:38 6:53:51
*/
public class ND {
static int[][] Map;
static boolean[] visited;
static List<LinkedList<Integer>> totalList;
static int MaxCount;
static int Count;
static int N;
static int R;
static int C;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();//点的个数
int M = sc.nextInt();
Map = new int[N][N];
totalList = new ArrayList<LinkedList<Integer>>();
for(int j=0;j<N;j++) {
LinkedList<Integer> itemList = new LinkedList<Integer>();
totalList.add(itemList);
}

for(int i=0;i<M;i++) {
int startPoint = sc.nextInt();
int endPoint = sc.nextInt();
List<Integer> itemsList = new LinkedList<Integer>();
itemsList.add(startPoint);
itemsList.add(endPoint);
totalList.get(itemsList.get(0)-1).add(itemsList.get(1)-1);
totalList.get(itemsList.get(1)-1).add(itemsList.get(0)-1);
}


MaxCount = 0;
for(int i=0;i<N;i++) {
visited = new boolean[N];
Count = 0;
if(totalList.get(i).size()>0)
DFS(i);
}

System.out.println(MaxCount);

}
private static void DFS(int i) {
// TODO Auto-generated method stub
MaxCount = MaxCount>Count?MaxCount:Count;
visited[i] = true;
for(Integer items : totalList.get(i)) {
if((!visited[items])) {
Count++;
DFS(items);
}
}
return;
}

}

输出:

写一个图的算法(一)_i++_12

有向图

写一个图的算法(一)_List_13

public class DirectGraph {
static int[][] Map;
static boolean[] visited;
static List<LinkedList<Integer>> totalList;
static int MaxCount;
static int Count;
static int N;
static int R;
static int C;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();//点的个数
int M = sc.nextInt();
Map = new int[N][N];
totalList = new ArrayList<LinkedList<Integer>>();
for(int j=0;j<N;j++) {
LinkedList<Integer> itemList = new LinkedList<Integer>();
totalList.add(itemList);
}

for(int i=0;i<M;i++) {
int startPoint = sc.nextInt();
int endPoint = sc.nextInt();
/*List<Integer> itemsList = new LinkedList<Integer>();
itemsList.add(startPoint);
itemsList.add(endPoint);*/
totalList.get(startPoint-1).add(endPoint-1);
//totalList.get(itemsList.get(1)-1).add(itemsList.get(0)-1);
}


MaxCount = 0;
for(int i=0;i<N;i++) {
visited = new boolean[N];
Count = 0;
if(totalList.get(i).size()>0)
DFS(i);
}

System.out.println(MaxCount);

}
private static void DFS(int i) {
// TODO Auto-generated method stub
MaxCount = MaxCount>Count?MaxCount:Count;
visited[i] = true;
for(Integer items : totalList.get(i)) {
if((!visited[items])) {
Count++;
DFS(items);
//Count--;
}
}
Count--;
return;
}

}

输出:

2

有向图要--

 

 

图的遍历-广度优先搜索

广度优先计算无向图的最短路径

广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。

算法步骤:

1. 首先将根节点放入队列中。

2. 从队列中取出第一个节点,并检验它是否为目标。

如果找到目标,则结束搜寻并回传结果。

否则将它所有尚未检验过的直接子节点加入队列中。

3. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传"找不到目标"。

4. 重复步骤2。

写一个图的算法(一)_List_14

 

广度一次将一个图的相邻节点全部遍历,然后遍历相邻节点的相邻节点,需要使用队列作为辅助的数据结构

计算0-6的最短路径

写一个图的算法(一)_i++_15

广度优先求最短路径

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class ShortestPath {
private Graph graph;
private boolean[] visited;
private int s;
private int[] form;
private int[] ords;
public ShortestPath(Graph graph, int s) {
super();
this.graph = graph;
this.s = s;
int V = graph.V();
visited = new boolean[V];
form = new int[V];
ords = new int[V];
Arrays.fill(form, -1);
Arrays.fill(ords, -1);

Queue<Integer> queue = new LinkedList<>();
queue.add(s);
ords[s] = 0;
visited[s] = true;
while(!queue.isEmpty()) {
Integer top = queue.poll();
for(int item:graph.adj(top)) {
if(!visited[item]) {
queue.add(item);
visited[item] = true;
form[item] = top;
ords[item] = ords[top]+1;
}
}
}
}

public boolean hasPath(int w) {
return visited[w];
}

public List<Integer> path(int w){
assert hasPath(w);
List<Integer> list = new ArrayList<>();
Deque<Integer> deque = new LinkedList<>();

int p = w;
while(p!=-1) {
deque.push(p);
p = form[p];
}

while(!deque.isEmpty()) {
list.add(deque.pop());
}
return list;
}

public void showPath(int w) {
assert hasPath(w);

List<Integer> path = path(w);
for(int i=0;i<path.size();i++) {
System.out.println(path.get(i));
if(i==path.size()-1) {
System.out.println();
}else {
System.out.print("->");
}
}
}

}

输出:

写一个图的算法(一)_List_16

ords距离0结点的距离

写一个图的算法(一)_java_17

form计算从那个结点过来的,用于输出路径

写一个图的算法(一)_i++_18

 

举报

相关推荐

0 条评论