建图的几种方式 邻接矩阵、邻接表、链式前向星
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| public static int MAXN = 11;
public static int MAXM = 21;
public static int[][] graph1 = new int[MAXN][MAXN];
public static ArrayList<ArrayList<int[]>> graph2 = new ArrayList<>();
public static int[] head = new int[MAXN];
public static int[] next = new int[MAXM];
public static int[] to = new int[MAXM];
public static int[] weight = new int[MAXM];
public static int cnt;
public static void build(int n) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { graph1[i][j] = 0; } } graph2.clear(); for (int i = 0; i <= n; i++) { graph2.add(new ArrayList<>()); } cnt = 1; Arrays.fill(head, 1, n + 1, 0); }
public static void addEdge(int u, int v, int w) { next[cnt] = head[u]; to[cnt] = v; weight[cnt] = w; head[u] = cnt++; }
public static void directGraph(int[][] edges) { for (int[] edge : edges) { graph1[edge[0]][edge[1]] = edge[2]; } for (int[] edge : edges) { graph2.get(edge[0]).add(new int[] { edge[1], edge[2] }); } for (int[] edge : edges) { addEdge(edge[0], edge[1], edge[2]); } }
public static void undirectGraph(int[][] edges) { for (int[] edge : edges) { graph1[edge[0]][edge[1]] = edge[2]; graph1[edge[1]][edge[0]] = edge[2]; } for (int[] edge : edges) { graph2.get(edge[0]).add(new int[] { edge[1], edge[2] }); graph2.get(edge[1]).add(new int[] { edge[0], edge[2] }); } for (int[] edge : edges) { addEdge(edge[0], edge[1], edge[2]); addEdge(edge[1], edge[0], edge[2]); } }
public static void traversal(int n) { System.out.println("邻接矩阵遍历 :"); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { System.out.print(graph1[i][j] + " "); } System.out.println(); } System.out.println("邻接表遍历 :"); for (int i = 1; i <= n; i++) { System.out.print(i + "(邻居、边权) : "); for (int[] edge : graph2.get(i)) { System.out.print("(" + edge[0] + "," + edge[1] + ") "); } System.out.println(); } System.out.println("链式前向星 :"); for (int i = 1; i <= n; i++) { System.out.print(i + "(邻居、边权) : "); for (int ei = head[i]; ei > 0; ei = next[ei]) { System.out.print("(" + to[ei] + "," + weight[ei] + ") "); } System.out.println(); } }
|
课程表二(拓扑排序)
leetcode 210
思路:判断入度,每次找到入度为0的点,加入队列,然后遍历这个点的所有边,将边指向的点的入度减1,如果减1后为0,则加入队列。最后判断加入队列的数量是否等于n,如果等于n,则说明有解,否则无解。排序结果就是这个队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public static int cnt;
public static void add(int u, int v,int[] head,int[] next,int[] to,int[] weight) { next[cnt] = head[u]; to[cnt] = v; head[u] = cnt++; weight[v]++; }
public static int[] findOrder(int numCourses, int[][] prerequisites) { cnt = 1; int n = numCourses; int m = prerequisites.length; int[] head = new int[n]; int[] next = new int[m+1]; int[] to = new int[m+1]; int[] weight = new int[n];
for(int i=0;i<m;i++){ add(prerequisites[i][1],prerequisites[i][0],head,next,to,weight); }
int[] queue = new int[n]; int l = 0; int r =0; for(int i =0;i<n;i++){ if(weight[i] == 0){ queue[r++] = i; } } int cnt =0; while(l<r){ int i = queue[l++]; cnt++; for(int ie = head[i];ie>0;ie = next[ie]){ int toi = to[ie]; if(--weight[toi] == 0){ queue[r++] = toi; } } } return cnt == n ? queue : new int[0]; }
|
火星词典
leetcode LCR114
思路:依次比较相邻的两个字符串,从字符串开头依次比较两个的字符。直到遇到不同的字符,那么就说明就是因为这个位置上的字符让前面的字符排在前面。于是增加一条从前面的字符指向后面的字符的边。这样得到一个图之后,就可以进行拓扑排序了。拓扑排序的结果就是字典序.但返回答案之前要判断得到的字典序里面的字符个数是否等于出现的字符个数,少了说明存在环,返回空字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| class Solution { public static int cnt;
public static void add(int u,int v,int[] head,int[] next,int[] to,int[] in){ next[cnt] = head[u]; to[cnt] = v; head[u] = cnt++; in[v]++; }
public String alienOrder(String[] words) { cnt = 1; int n = words.length; int[] cnt = new int[26]; Arrays.fill(cnt,-1); for(int i=0;i<n;i++){ String s = words[i]; for(int j=0;j<s.length();j++){ if(cnt[s.charAt(j)-'a'] == -1){ cnt[s.charAt(j)-'a'] = 0; } } } int[] head = new int[26]; int[] next = new int[26*26+10]; int[] to = new int[26*26+10]; for(int i=0,j;i<n-1;i++){ String cur = words[i]; String curNext = words[i+1]; int len = Math.min(cur.length(),curNext.length()); j=0; for(;j<len;j++){ if(cur.charAt(j)!=curNext.charAt(j)){ add(cur.charAt(j) - 'a',curNext.charAt(j)-'a',head,next,to,cnt); break; } } if( j<cur.length() && j == curNext.length()){ return ""; } } int kinds = 0; int[] queue = new int[26]; int l =0; int r = 0; for(int i=0;i<26;i++){ if(cnt[i] != -1){ kinds++; } if(cnt[i] == 0){ queue[r++] = i; } } StringBuilder sb = new StringBuilder(); while(l<r){ int temp = queue[l++]; char ansChar = (char)('a' + temp); kinds --; sb.append(ansChar); for(int ie = head[temp];ie>0;ie = next[ie]){ if(--cnt[to[ie]] == 0){ queue[r++] = to[ie]; } } } return kinds == 0 ? sb.toString(): ""; } }
|
最大食物链计数
思路:拓扑排序,只不过每次出队时的节点要把自己的信息告诉自己的邻居节点。(其实这道题也能用dfs,而且更简单)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| public class Code01_FoodLines {
public static int MAXN = 5001;
public static int MAXM = 500001;
public static int MOD = 80112002;
public static int[] head = new int[MAXN];
public static int[] next = new int[MAXM];
public static int[] to = new int[MAXM];
public static int cnt;
public static int[] queue = new int[MAXN];
public static int[] indegree = new int[MAXN];
public static int[] lines = new int[MAXN];
public static int n, m;
public static void build(int n) { cnt = 1; Arrays.fill(indegree, 0, n + 1, 0); Arrays.fill(lines, 0, n + 1, 0); Arrays.fill(head, 0, n + 1, 0); }
public static void addEdge(int u, int v) { next[cnt] = head[u]; to[cnt] = v; head[u] = cnt++; }
public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StreamTokenizer in = new StreamTokenizer(br); PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int) in.nval; in.nextToken(); m = (int) in.nval; build(n); for (int i = 0, u, v; i < m; i++) { in.nextToken(); u = (int) in.nval; in.nextToken(); v = (int) in.nval; addEdge(u, v); indegree[v]++; } out.println(ways()); } out.flush(); out.close(); br.close(); }
public static int ways() { int l = 0; int r = 0; for (int i = 1; i <= n; i++) { if (indegree[i] == 0) { queue[r++] = i; lines[i] = 1; } } int ans = 0; while (l < r) { int u = queue[l++]; if (head[u] == 0) { ans = (ans + lines[u]) % MOD; } else { for (int ei = head[u], v; ei > 0; ei = next[ei]) { v = to[ei]; lines[v] = (lines[v] + lines[u]) % MOD; if (--indegree[v] == 0) { queue[r++] = v; } } } } return ans; }
}
|
喧闹与富有
leetcode 851
思路:拓扑排序,但出队的时候把自己的答案推送到下一个节点即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| class Solution { public static int cnt;
public static void add(int u,int v,int[] head,int[] next,int[] to,int[] in){ next[cnt] = head[u]; to[cnt] = v; head[u] = cnt++; in[v]++; }
public int[] loudAndRich(int[][] richer, int[] quiet) { cnt=1; int n = quiet.length; int m = richer.length; int[] head = new int[n]; int[] next = new int[m+1]; int[] to = new int[m+1]; int[] in = new int[n]; int[] ans = new int[n]; for(int i=0;i<n;i++){ ans[i] = i; } for(int i=0;i<m;i++){ add(richer[i][0],richer[i][1],head,next,to,in); } int[] queue = new int[n]; int l=0; int r =0; for(int i =0;i<n;i++){ if(in[i] == 0){ queue[r++] = i; } } while(l<r){ int pos = queue[l++]; for(int ie = head[pos];ie>0;ie = next[ie]){ int nextP = to[ie]; if(quiet[ans[pos]] < quiet[ans[nextP]]){ ans[nextP] = ans[pos]; } if(--in[nextP] == 0){ queue[r++] = nextP; } } } return ans; } }
|
以上就是图论基本内容,其实就是建图加拓扑排序。或者有简单的bfs或者dfs。 至于更复杂的图论,以后再学吧。