【算法】图论学习笔记与代码实现
這學(xué)期兩門主課?算法設(shè)計與分析(Algorithm and Analysis,ADA)?和 圖論與算法(Graph Theory and Algorithms, GTA) 都涉及到很多經(jīng)典圖論問題以及相關(guān)代碼實(shí)現(xiàn),遂寫下此文,以記錄學(xué)習(xí)過程,隨緣更新。
深度優(yōu)先遍歷(經(jīng)典DFS):
從圖中某一個節(jié)點(diǎn)出發(fā),如果有未探索的鄰居節(jié)點(diǎn),則選擇其中應(yīng)該進(jìn)行深入探索(其他節(jié)點(diǎn)暫時不管),每到一個新的節(jié)點(diǎn)則遞歸進(jìn)行上述過程。當(dāng)探索無法繼續(xù)時(當(dāng)前節(jié)點(diǎn)的所有鄰居都在前面的探索過程中被標(biāo)記過),則沿原路徑回退。回退到某個節(jié)點(diǎn)時,若它還有其他的鄰居節(jié)點(diǎn)沒有探索,則繼續(xù)深入探索。
使用白色,黑色,灰色記錄每個節(jié)點(diǎn)的狀態(tài):
白色:表示一個節(jié)點(diǎn)尚未被遍歷;
灰色:表示一個節(jié)點(diǎn)已經(jīng)被遍歷到,但是對于它的遍歷尚未結(jié)束;即該節(jié)點(diǎn)還有若干鄰居節(jié)點(diǎn)等待遍歷,而當(dāng)前算法正在遞歸處理其中一個鄰居節(jié)點(diǎn);
黑色:表示一個節(jié)點(diǎn)的所有鄰居已經(jīng)完成遍歷,其自身的遍歷也結(jié)束。
框架代碼(包括封裝和實(shí)現(xiàn)兩部分):
具體實(shí)現(xiàn)(根據(jù)DFS遍歷順序簡單輸出一下各個節(jié)點(diǎn)的編號):
// DFS #include <iostream> #define N 10000 using namespace std;int graph[N][N]; int color[N]; // 0 white, 1 grey, 2 black int n, m;void dfs(int v) {color[v] = 1;for (int i = 1; i <= n; i++){if (i != v && graph[v][i] == 1){if (color[i] == 0){dfs(i);}}}cout << v << " ";color[v] = 2; }void my_dfs() {for (int i = 1; i <= n; i++){if (color[i] == 0)dfs(i);}cout << endl; }int main() {cin >> n >> m;for (int i = 0; i < m; i++){int x, y;cin >> x >> y;graph[x][y] = 1;}my_dfs();return 0; }/* input: 7 13 1 2 1 3 1 6 2 3 2 4 4 1 4 3 5 3 5 7 6 1 6 3 7 4 7 5output: 3 4 2 6 1 7 5 */廣度優(yōu)先遍歷(BFS):
從圖中某個節(jié)點(diǎn)出發(fā),首先處理該節(jié)點(diǎn)指向鄰居的所有邊,然后將所有鄰居放入一個調(diào)度器——隊列(queue)中,接著處理該節(jié)點(diǎn)。下一個遍歷的節(jié)點(diǎn)從當(dāng)前被發(fā)現(xiàn)但未被處理的點(diǎn)中選出,即隊列的首個節(jié)點(diǎn),然后將其鄰居節(jié)點(diǎn)依次放入隊尾,處理該節(jié)點(diǎn)自身。重復(fù)以上過程,直到隊列為空,所有節(jié)點(diǎn)均被處理完畢。
仍然以上面的圖為例,輸出BFS順序遍歷每個節(jié)點(diǎn)的值:
// BFS #include <iostream> #include <queue> #define N 10000 using namespace std;int graph[N][N]; int color[N]; // 0 white, 1 grey, 2 black int parent[N]; int dis[N]; int n, m;void bfs(int v) {queue<int> que;color[v] = 1; // greydis[v] = 0; // 源點(diǎn)que.push(v);while(!que.empty()){int w = que.front();que.pop();for (int i = 1; i < n; i++){if (i != w && graph[w][i] == 1){if (color[i] == 0){color[i] = 1; //greyparent[i] = w;dis[i] = dis[w] + 1;que.push(i);}}}cout << w << " ";color[w] = 2; // black} }void my_bfs() {for (int i = 1; i <= n; i++){color[i] = 0;parent[i] = 0;dis[i] = 0;}for (int i = 1; i <= n; i++){if (color[i] == 0)bfs(i);}cout << endl; }int main() {cin >> n >> m;for (int i = 0; i < m; i++){int x, y;cin >> x >> y;graph[x][y] = 1;}my_bfs();return 0; }/* input: 7 13 1 2 1 3 1 6 2 3 2 4 4 1 4 3 5 3 5 7 6 1 6 3 7 4 7 5 output: 1 2 3 6 4 5 7 */網(wǎng)絡(luò)中的最大流:
題目描述:
給定n個點(diǎn),m條有向邊,給定每條邊的容量,求從點(diǎn)s到點(diǎn)t的最大流
輸入:
第一行四個整數(shù)n,m,s,t。
接下來的m行,每行三個整數(shù)u,v,c,表示u到v,流量為c的一條邊,
輸出:
輸出點(diǎn)s到點(diǎn)t的最大流。
樣例輸入 :
7 14 1 7 1 2 5 1 3 6 1 4 5 2 3 2 2 5 3 3 2 2 3 4 3 3 5 3 3 6 7 4 6 5 5 6 1 6 5 1 5 7 8 6 7 7樣例輸出 :
14
提示:
1<=n<=100,1<=m<=5000,0<=c<=2147483647
#include <iostream> #include <cstring> using namespace std;const int N = 10001, E = 200001;int n, m, s, t; long long ans = 0; long long cnt = 1, first[N], nxt[E], to[E], val[E];inline void addE(int u, int v, long long w) {to[++cnt] = v;val[cnt] = w;nxt[cnt] = first[u];first[u] = cnt; }int dep[N], q[N], l, r;bool bfs() { memset(dep, 0, (n + 1) * sizeof(int));q[l = r = 1] = s;dep[s] = 1;while (l <= r) {int u = q[l++];for (int p = first[u]; p; p = nxt[p]) {int v = to[p];if (val[p] and !dep[v]) { dep[v] = dep[u] + 1;q[++r] = v;}}}return dep[t]; }long long dfs(int u, long long in) {if (u == t)return in;long long out = 0;for (int p = first[u]; p and in; p = nxt[p]){int v = to[p];if (val[p] and dep[v] == dep[u] + 1) {long long res = dfs(v, min(val[p], in));val[p] -= res;val[p ^ 1] += res;in -= res;out += res;}}if (out == 0)dep[u] = 0;return out; }int main() {cin >> n >> m >> s >> t;for (int i = 1; i <= m; i++) {int u, v; long long w;cin >> u >> v >> w;addE(u, v, w);addE(v, u, 0);}while (bfs())ans += dfs(s, 1e18);cout << ans << endl;return 0; } /**************************************************************Problem: 1006User: 201830210Language: C++Result: 正確Time:56 msMemory:0 kb ****************************************************************/二分圖中的最大匹配問題:
題目描述:
給定一個二分圖,其左部點(diǎn)的個數(shù)為n,右部點(diǎn)的個數(shù)為m,邊數(shù)為e,求其最大匹配的邊數(shù)。
左部點(diǎn)從1至n編號,右部點(diǎn)從1至m編號。
輸入:
輸入的第一行是三個整數(shù),分別代表n,m,e。
接下來輸入e行,每行兩個整數(shù)u,v,表示存在一條連接左部點(diǎn)u和右部點(diǎn)v的邊。
輸出:
輸出一個整數(shù),代表二分圖最大匹配的邊數(shù)。
樣例輸入:
4 2 7 3 1 1 2 3 2 1 1 4 2 4 1 1 1樣例輸出:
2
提示:
1<= n,m <=100
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std;int n,m; int cnt=2; int alist[6000001]; struct data {int v;int next;int value; }edge[6000001];void add(int u,int v,int value) {edge[cnt].v=v;edge[cnt].value=value;edge[cnt].next=alist[u];alist[u]=cnt++;return ; } int h[1000001]; int q[1000001];bool bfs() {int x,next;memset(h,-1,sizeof(h));int head=0,tail=1;q[head]=1;h[1]=0;while(head<tail){x=q[head++];next=alist[x];while(next){int v=edge[next].v;int value=edge[next].value;if(value&&h[v]<0){q[tail++]=v;h[v]=h[x]+1;}next=edge[next].next;}}if(h[n]==-1) return false;return true; }int ans; int dfs(int x,int y) {if(x==n) return y;int next=alist[x];int w,used=0;while(next){int v=edge[next].v;int value=edge[next].value;if(value&&h[v]==h[x]+1){w=y-used;w=dfs(v,min(w,value));edge[next].value-=w;edge[next^1].value+=w;used+=w;if(used==y) return y;}next=edge[next].next;}if(!used) h[x]=-1;return used; } void dinic() {while(bfs()) ans+=dfs(1,0x7fffffff); } int n1,m1,e1; int main() {scanf("%d%d%d",&n1,&m1,&e1);n=n1+m1+2;for(int i=1;i<=n1;i++){add(1,i+1,1);add(i+1,1,1);}for(int i=1;i<=e1;i++){int u,v;scanf("%d%d",&u,&v);if(u<=n1&&v<=m1)add(u+1,v+n1+1,1),add(v+n1+1,u+1,1);}for(int i=1;i<=m1;i++){add(i+n1+1,n,1);add(n,i+n1+1,1);}dinic();printf("%d",ans);return 0; } /**************************************************************Problem: 1005User: 201830210Language: C++Result: 正確Time:9 msMemory:0 kb ****************************************************************/總結(jié)
以上是生活随笔為你收集整理的【算法】图论学习笔记与代码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数据结构】树状数组详解(Leetcod
- 下一篇: 微信小程序- 初试小程序之tabbar(