博客作業--圖
1.學習總結
1.1圖的思維導圖
1.2 圖結構學習體會
- 深度遍歷算法、廣度遍歷算法:容易理解,便於找尋,比較基礎
- Prim和Kruscal算法:都是從連通圖中找出最小生成樹的算法。Prim算法直接查找,多次尋找鄰邊的權重最小值,而Kruskal是需要先對權重排序後查找的,則Kruskal算法效率比Prim快。
- Dijkstra算法:使用了廣度優先搜索解決賦權有向圖最短路徑問題,以起始點為中心向外層層擴展,直到擴展到終點為止,最終得到一個最短路徑
- 拓撲排序算法:並不一定唯一,要有向圖以及判斷有沒有環路
2.PTA實驗作業
2.1 題目1:7-1 圖著色問題
2.2 設計思路
將兩頂點之間建立一條無向邊,c用來標記已經查到不符合條件的邊,即有邊的兩個頂點是同一種顏色,sum來記錄該方案中出現的顏色種類。
每一輪都要將f刷為0, if(f[h[j]]==0)查看該種顏色是否是新出現的顏色。
如果c不等於0,說明已經查到不符合條件的邊。
如果顏色的種類已經超過k種,說明不可行,不用繼續查找;如果查到有不符合條件的邊,或者方案中使用的顏色種類不是k中,也說明不可行。
2.3 代碼截圖
2.4 PTA提交列表說明。
開始只是簡單按照題目要求,後來通過借鑒發現按照存在邊的兩點的顏色不能是同一種顏色以及每一種著色方案使用的顏色個數要正好是k種這兩個條件就可以解決問題,於是才答案正確。PTA提交時開始有一處未加分號導致編譯錯誤,後未選用C++導致編譯錯誤,改正後正確。
2.1 題目2:題目名稱
2.2 設計思路
先創建find函數來尋找一個點的最後一個節點,如果沒到最後一個,就往下一個尋找;
創建add合並函數,用來對自己的下一個點賦值;
最後使用main函數進行判斷和輸出。
2.3 代碼截圖
2.4 PTA提交列表說明。
本題較難,最開始使用二維數組進行編寫,得出代碼復雜,改錯困難,後和同學商討後發現要用並查集的方法,於是上網借鑒代碼理解後寫出正確代碼。
2.1 題目3:7-4 公路村村通
2.2 設計思路
建立cmp和find函數聯通並查集,n個村莊可修n-1條路,用kruskal算法找最小生成樹 ,最後用main得出結果。
2.3 代碼截圖
2.4 PTA提交列表說明。
開始使用prime算法,但由於對知識不熟練導致程序無法正常得出結果,後參考後得以成功運行。之後借鑒較高效的Kruscal算法,同樣得出正確結果。
3.截圖本周題目集的PTA最後排名
3.1 PTA排名
3.2 我的總分:
4. 閱讀代碼
7-9 天梯地圖
- #include <cstdio>
- #include <algorithm>
- #include <vector>
- using namespace std;
- const int inf = 999999999;
- int dis[510], Time[510], e[510][510], w[510][510], Timepre[510], weight[510];
- bool visit[510];
- vector<int> Timepath, dispath, temppath, dispre[510];
- int st, fin, minnode = inf;
- void dfsTimepath(int v) {
- Timepath.push_back(v);
- if(v == st) {
- return ;
- }
- dfsTimepath(Timepre[v]);
- }
- void dfsdispath(int v) {
- temppath.push_back(v);
- if(v == st) {
- if(temppath.size() < minnode) {
- minnode = temppath.size();
- dispath = temppath;
- }
- temppath.pop_back();
- return ;
- }
- for(int i = 0; i < dispre[v].size(); i++) {
- dfsdispath(dispre[v][i]);
- }
- temppath.pop_back();
- }
- int main() {
- fill(dis, dis + 510, inf);
- fill(Time, Time + 510, inf);
- fill(weight, weight + 510, inf);
- fill(e[0], e[0] + 510 * 510, inf);
- fill(w[0], w[0] + 510 * 510, inf);
- int n, m;
- scanf("%d %d", &n, &m);
- int a, b, flag, len, t;
- for(int i = 0; i < m; i++) {
- scanf("%d %d %d %d %d", &a, &b, &flag, &len, &t);
- e[a][b] = len;
- w[a][b] = t;
- if(flag != 1) {
- e[b][a] = len;
- w[b][a] = t;
- }
- }
- scanf("%d %d", &st, &fin);
- Time[st] = 0;
- for(int i = 0; i < n; i++) {
- Timepre[i] = i;
- }
- for(int i = 0; i < n; i++) {
- int u = -1, minn = inf;
- for(int j = 0; j < n; j++) {
- if(visit[j] == false && Time[j] < minn) {
- u = j;
- minn = Time[j];
- }
- }
- if(u == -1) break;
- visit[u] = true;
- for(int v = 0; v < n; v++) {
- if(visit[v] == false && w[u][v] != inf) {
- if(w[u][v] + Time[u] < Time[v]) {
- Time[v] = w[u][v] + Time[u];
- Timepre[v] = u;
- weight[v] = weight[u] + e[u][v];
- } else if(w[u][v] + Time[u] == Time[v] && weight[v] > weight[u] + e[u][v]) {
- weight[v] = weight[u] + e[u][v];
- Timepre[v] = u;
- }
- }
- }
- }
- dfsTimepath(fin);
- fill(visit, visit + 510, false);
- dis[st] = 0;
- for(int i = 0; i < n; i++) {
- int u = -1, minn = inf;
- for(int j = 0; j < n; j++) {
- if(visit[j] == false && minn > dis[j]) {
- u = j;
- minn = dis[j];
- }
- }
- if(u == -1) break;
- visit[u] = true;
- for(int v = 0; v < n; v++) {
- if(visit[v] == false && e[u][v] != inf) {
- if(e[u][v] + dis[u] < dis[v]) {
- dis[v] = e[u][v] + dis[u];
- dispre[v].clear();
- dispre[v].push_back(u);
- } else if(e[u][v] + dis[u] == dis[v]) {
- dispre[v].push_back(u);
- }
- }
- }
- }
- dfsdispath(fin);
- printf("Time = %d", Time[fin]);
- if(dispath == Timepath) {
- printf("; Distance = %d: ", dis[fin]);
- } else {
- printf(": ");
- for(int i = Timepath.size() - 1; i >= 0; i--) {
- printf("%d", Timepath[i]);
- if(i != 0) printf(" => ");
- }
- printf("\n");
- printf("Distance = %d: ", dis[fin]);
- }
- for(int i = dispath.size() - 1; i >= 0; i--) {
- printf("%d", dispath[i]);
- if(i != 0) printf(" => ");
- }
- return 0;
- }
用兩個Dijkstra + DFS。一個求最快路徑(如果相同求路徑的那條),一個求最短路徑(如果相同求結點數最小的那條)。求最快路徑可以直接在Dijkstra裏面求前驅結點Timepre數組。求最短路徑因為要求結點數最小的那條,所以要用dispre的二維數組存儲所有結點的最短路徑,然後用DFS求出滿足條件的結點數最小的那條。
博客作業--圖