#include<algorithm>#include<cstring>// memset#include<iostream>usingnamespace std;constint N =1e5+10, M =2* N;int n, m;// head, e[M],ne[M],idx; 是一條單鏈表// h[N], e[M],ne[M],idx; 是N條單鏈表int h[N], e[M], ne[M], idx;bool st[N];// 用st數(shù)組存一下哪些點已經(jīng)被遍歷過了int ans = N;//記錄一個全局最大值// 在a對應的單鏈表中插入一個節(jié)點bvoidadd(int a,int b){e[idx]= b;// 表示第idx條邊指向b點ne[idx]= h[a];// ne[idx]表示第idx條邊的下一條邊是 a點的鄰接鏈表的第一條邊h[a]= idx++;// head[a]表示將a點的鄰接鏈表的第一條邊更新為第idx條邊}// u表示當前已經(jīng)dfs到的這個點// 以u為根的子樹中, 點的數(shù)量intdfs(int u){st[u]=true;// 標記一下, 當前這個點已經(jīng)被搜索過int sum =1;// 記錄當前子樹大小int res =0;// 把u這個點刪除之后, 每一個聯(lián)通塊的最大值for(int i = h[u]; i !=-1; i = ne[i]){int j = e[i];// 當前這個鏈表中的節(jié)點, 對應圖中的點的編號是多少if(!st[j]){int s =dfs(j);// j這棵子樹的大小res =max(res, s);//最大的聯(lián)通塊大小sum += s;}}res =max(res, n - sum);ans =min(ans, res);return sum;}intmain(){// 一條單鏈表 head初始化為-1// n條單鏈表,把所有的head初始化為-1memset(h,-1,sizeof h);cin >> n;for(int i =0; i < n -1; i++){int a, b;cin >> a >> b;add(a, b);add(b, a);}// 隨便挑一個點, 比方說從第一個點開始搜dfs(1);cout << ans << endl;return0;}
樹與圖的廣度優(yōu)先遍歷
圖中點的層次
建圖然后bfs;dist表示距離,-1表示走不到,初始化為-1
#include<iostream>#include<cstring>#include<queue>usingnamespace std;constint N =1e5+10;int n, m;int h[N], e[N], ne[N], idx;int dist[N];voidadd(int a,int b){e[idx]= b;ne[idx]= h[a];h[a]= idx ++;}intbfs(){memset(dist,-1,sizeof dist);queue<int> q;q.push(1);dist[1]=0;while(q.size()){auto t = q.front();q.pop();for(int i = h[t]; i !=-1; i = ne[i]){int j = e[i];if(dist[j]==-1){dist[j]= dist[t]+1;q.push(j);}}}return dist[n];}intmain(){memset(h,-1,sizeof h);scanf("%d%d",&n,&m);for(int i =0; i < m; i ++){int a, b;scanf("%d%d",&a,&b);add(a, b);}printf("%d\n",bfs());}
拓撲排序
有向圖的拓撲序列
有向無環(huán)圖也被稱為拓撲圖
拓撲序列 :所有的邊都從前指向后,那么所有入度為0的點都可以作為起點
#include<iostream>#include<cstring>#include<queue>usingnamespace std;constint N =1e5+10;int h[N], e[N], ne[N], idx;int top[N];int d[N];int cnt =0;int n, m;voidadd(int a,int b){e[idx]= b, ne[idx]= h[a], h[a]= idx ++;}booltopsort(){queue<int> q;for(int i =1; i <= n; i ++)if(!d[i])q.push(i);while(q.size()){auto t = q.front();q.pop();top[cnt ++]= t;for(int i = h[t]; i !=-1; i = ne[i]){int j = e[i];d[j]--;if(!d[j])q.push(j);}}return cnt == n;}intmain(){cin >> n >> m;memset(h,-1,sizeof h);for(int i =0; i < m; i ++){int a, b;cin >> a >> b;add(a, b);d[b]++;}if(!topsort())puts("-1");else{for(int i =0; i < n; i ++){cout << top[i];if(i != n -1) cout <<' ';}}return0;}#include<iostream>#include<cstring>usingnamespace std;constint N =1e5+10;int h[N], e[N], ne[N], idx;int q[N];int d[N];int n, m;voidadd(int a,int b){e[idx]= b, ne[idx]= h[a], h[a]= idx ++;}booltopsort(){int hh =0, tt =-1;for(int i =1; i <= n; i ++)if(!d[i])q[++ tt]= i;while(hh <= tt){auto t = q[hh ++];for(int i = h[t]; i !=-1; i = ne[i]){int j = e[i];d[j]--;if(!d[j])q[++ tt]= j;}}return tt +1== n;}intmain(){memset(h,-1,sizeof h);cin >> n >> m;for(int i =0; i < m; i ++){int a, b;cin >> a >> b;add(a, b);d[b]++;}if(!topsort())puts("-1");else{for(int i =0; i < n; i ++){cout << q[i];if(i != n -1) cout <<' ';}}return0;}
#include<iostream>#include<cstring>usingnamespace std;constint N =510;int g[N][N];int dist[N];bool st[N];int n, m;intdijkstra(){memset(dist,0x3f,sizeof dist);dist[1]=0;for(int i =0; i < n -1; i ++){int t =-1;for(int j =1; j <= n; j ++)if(!st[j]&&(t ==-1|| dist[t]> dist[j]))t = j;for(int j =1; j <= n; j ++)dist[j]=min(dist[j], dist[t]+ g[t][j]);st[t]=true;}if(dist[n]==0x3f3f3f3f)return-1;return dist[n];}intmain(){memset(g,0x3f,sizeof g);cin >> n >> m;for(int i =0; i < m; i ++){int a, b, c;cin >> a >> b >> c;g[a][b]=min(g[a][b], c);}printf("%d",dijkstra());return0;}
#include<algorithm>#include<cstring>#include<iostream>usingnamespace std;constint N =510, M =10010;structEdge{int a, b, c;} edges[M];int n, m, k;int dist[N];int last[N];voidbellman_ford(){memset(dist,0x3f,sizeof dist);dist[1]=0;for(int i =0; i < k; i++){memcpy(last, dist,sizeof dist);//只用上一次迭代的結果for(int j =0; j < m; j++){auto e = edges[j];dist[e.b]=min(dist[e.b], last[e.a]+ e.c);}}}intmain(){cin >> n >> m >> k;for(int i =0; i < m; i++){int a, b, c;cin >> a >> b >> c;edges[i]={a, b, c};}bellman_ford();if(dist[n]>0x3f3f3f3f/2){cout <<"impossible"<< endl;}else{cout << dist[n]<< endl;}return0;}
#include<cstring>#include<iostream>#include<queue>usingnamespace std;constint N =2e3+10, M =1e4+10;int n, m;int head[N], e[M], ne[M], w[M], idx;bool st[N];int dist[N];// 表示 當前從1 -> x的最短距離int cnt[N];//cnt[x] 表示 當前從1 -> x的最短路的邊數(shù)voidadd(int a,int b,int c){e[idx]= b;ne[idx]= head[a];w[idx]= c;head[a]= idx++;}boolspfa(){// 這里不需要初始化dist數(shù)組為 正無窮/初始化的原因是, 如果存在負環(huán), 那么dist不管初始化為多少, 都會被更新queue<int> q;//不僅僅是1了, 因為點1可能到不了有負環(huán)的點, 因此把所有點都加入隊列for(int i=1;i<=n;i++){q.push(i);st[i]=true;}while(q.size()){int t = q.front();q.pop();st[t]=false;for(int i = head[t];i!=-1; i=ne[i]){int j = e[i];if(dist[j]>dist[t]+w[i]){dist[j]= dist[t]+w[i];cnt[j]= cnt[t]+1;if(cnt[j]>=n){// 有n條邊,則n + 1個點,抽屜原理,有兩個點是同一個點,則說明路徑上存在環(huán),又因為路徑變小,說明存在負環(huán)returntrue;}if(!st[j]){q.push(j);st[j]=true;}}}}returnfalse;}intmain(){cin >> n >> m;memset(head,-1,sizeof head);for(int i =0; i < m; i++){int a, b, c;cin >> a >> b >> c;add(a, b, c);}if(spfa()){cout <<"Yes"<< endl;}else{cout <<"No"<< endl;}return0;}
Floyd
Floyd求最短路
D[k, i, j]表示“經(jīng)過若干個編號不超過k的結點“從i到j的最短路徑,該問題可劃分為兩個子問題,經(jīng)過編號不超過k-1的點從i到j,或者從i先到k再到j,D[k,i,j]=min(D[k?1,i,j],D[k?1][i][k]+D[k?1][k][j])D[k,i,j]=min(D[k-1,i,j],D[k-1][i][k]+D[k-1][k][j])D[k,i,j]=min(D[k?1,i,j],D[k?1][i][k]+D[k?1][k][j]),初值為D[0,i,j]=A[i,j]D[0,i,j]=A[i,j]D[0,i,j]=A[i,j],其中A[i,j]是開頭定義的鄰接矩陣
#include<algorithm>#include<cstring>#include<iostream>usingnamespace std;constint N =210, INF =1e9;int n, m, Q;int d[N][N];voidfloyd(){for(int k =1; k <= n; k++){for(int i =1; i <= n; i++){for(int j =1; j <= n; j++){d[i][j]=min(d[i][j], d[i][k]+ d[k][j]);}}}}intmain(){cin >> n >> m >> Q;for(int i =1; i <= n; i++){for(int j =1; j <= n; j++){if(i == j){d[i][j]=0;}else{d[i][j]= INF;}}}while(m--){int a, b, c;cin >> a >> b >> c;d[a][b]=min(d[a][b], c);}floyd();while(Q--){int a, b;cin >> a >> b;int t = d[a][b];if(t > INF /2){cout <<"impossible"<< endl;}else{cout << t << endl;}}return0;}
#include<iostream>#include<algorithm>usingnamespace std;constint N =1e5+10, M =2e5+10, INF =0x3f3f3f3f;int n, m;int fa[N];structEdge{int a, b, w;booloperator<(const Edge &W)const{return w < W.w;}}edges[M];intfind(int x){if(fa[x]!= x) fa[x]=find(fa[x]);return fa[x];}intkruskai(){for(int i =1; i <= n; i ++) fa[i]= i;// 初始化并查集int res =0, cnt =0;1for(int i =0; i < m; i ++){int a = edges[i].a, b = edges[i].b, w = edges[i].w;a =find(a), b =find(b);if(a != b){res += w;cnt ++;fa[a]= b;}}if(cnt < n -1)return INF;return res;}intmain(){cin >> n >> m;for(int i =0; i < m; i ++)cin >> edges[i].a >> edges[i].b >> edges[i].w;sort(edges, edges + m);// 排序int t =kruskai();if(t == INF)puts("impossible");elsecout << t;return0;}
染色法判定二分圖
染色法判定二分圖
二分圖 :當且僅當圖中沒有奇數(shù)環(huán),劃分為兩個集合,集合內(nèi)部沒有邊
#include<iostream>#include<algorithm>#include<cstring>usingnamespace std;constint N =1e5+10, M =2* N;// 無向圖,邊存兩次,數(shù)組兩倍int h[N], e[M], ne[M], idx;int co[N];int n, m;voidadd(int a,int b){e[idx]= b, ne[idx]= h[a], h[a]= idx ++;}booldfs(int u,int c){co[u]= c;for(int i = h[u]; i !=-1; i = ne[i]){int j = e[i];if(!co[j]&&!dfs(j,3- c))returnfalse;elseif(co[j]== c)returnfalse;}returntrue;}intmain(){memset(h,-1,sizeof h);cin >> n >> m;for(int i =0; i < m; i ++){int u, v;cin >> u >> v;add(u, v);add(v, u);// 無向圖}bool success =true;for(int i =1; i <= n; i ++)// 圖可能不連通if(!co[i]&&!dfs(i,1)){success =false;break;}if(success)puts("Yes");elseputs("No");return0;}
#include<iostream>#include<cstring>usingnamespace std;constint N =510, M =1e5+10;int h[N], e[M], ne[M], idx;bool st[N];// st數(shù)組代表對于當前左部節(jié)點,右部的這個節(jié)點在它這輪的匹配中是否被“詢問”過;在同一輪中不要重復詢問同一個點int match[N];int n1, n2, m;voidadd(int a,int b){e[idx]= b, ne[idx]= h[a], h[a]= idx ++;}boolfind(int x){for(int i = h[x]; i !=-1; i = ne[i]){int j = e[i];if(!st[j]){st[j]=true;if(match[j]==0||find(match[j])){match[j]= x;returntrue;}}}returnfalse;}intmain(){memset(h,-1,sizeof h);cin >> n1 >> n2 >> m;for(int i =0; i < m; i ++){int a, b;cin >> a >> b;add(a, b);// add(b, a); 從左部匹配右部,所以即使無向圖,加了會wa}int res =0;for(int i =1; i <= n1; i ++){memset(st,0,sizeof st);if(find(i)) res ++;}cout << res << endl;return0;}