图论

来源:互联网 发布:everying软件 编辑:程序博客网 时间:2024/06/09 18:21





强连通分量


POJ 2186 popular cow 从一个没有入度的连通分量遍历图

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;int n, m;vector<vector<int> > g(10010);vector<vector<int> > rg(10010);vector<int> order;int cnt;int visited[10010];int color[10010];void dfs(int v){visited[v] = 1;for (int i = 0; i < g[v].size(); i++){if (!visited[g[v][i]])dfs(g[v][i]);}order.push_back(v);}void rdfs(int v, int k){color[v] = k;visited[v] = 1;for (int i = 0; i < rg[v].size(); i++){if (!visited[rg[v][i]])rdfs(rg[v][i], k);}}int main(){scanf("%d%d", &n, &m);int a, b;for (int i = 0; i < m; i++){scanf("%d%d", &a, &b);g[a].push_back(b);rg[b].push_back(a);}memset(visited, 0, sizeof(visited));for (int i = 1; i <= n; i++){if (!visited[i])dfs(i);}cnt = 0;memset(visited, 0, sizeof(visited));for (int i = order.size() - 1; i >= 0; i--){if (!visited[order[i]])rdfs(order[i], cnt++);}int ans = 0;int u;for (int i = 1; i <= n; i++)if (color[i] == cnt - 1){ans++;u = i;}memset(visited, 0, sizeof(visited));rdfs(u, 0);for (int i = 1; i <= n; i++)if (visited[i] == 0){ans = 0;break;}printf("%d\n", ans);}


POJ 2186 popular cow 看每个连通分量的入度

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;int n, m;vector<vector<int> > g(10010);vector<vector<int> > rg(10010);vector<int> order;int cnt;int visited[10010];vector<vector<int> > colorSet;int colorHash[10010];void dfs(int v){visited[v] = 1;for (int i = 0; i < g[v].size(); i++){if (!visited[g[v][i]])dfs(g[v][i]);}order.push_back(v);}void rdfs(int v, int k){colorSet[k].push_back(v);colorHash[v] = k;visited[v] = 1;for (int i = 0; i < rg[v].size(); i++){if (!visited[rg[v][i]])rdfs(rg[v][i], k);}}int main(){scanf("%d%d", &n, &m);int a, b;for (int i = 0; i < m; i++){scanf("%d%d", &a, &b);g[a].push_back(b);rg[b].push_back(a);}memset(visited, 0, sizeof(visited));for (int i = 1; i <= n; i++){if (!visited[i])dfs(i);}cnt = 0;memset(visited, 0, sizeof(visited));for (int i = order.size() - 1; i >= 0; i--){if (!visited[order[i]]){colorSet.push_back(vector<int>());rdfs(order[i], cnt++);}}int ans = 0;int endPoint = 0;for (int i = 0; i < colorSet.size(); i++)//每个连通分支{int tag = 0;for (int j = 0; j < colorSet[i].size(); j++)//每个连通分支的每个点{int u = colorSet[i][j];for (int k = 0; k < g[u].size(); k++)//一个连通分支的一个点的边{if (colorHash[g[u][k]] != i){tag = 1;break;}}if (tag == 1)break;}if (tag == 0){endPoint++;ans = colorSet[i].size();}}if (endPoint != 1)ans = 0;printf("%d\n", ans);}


POJ 1236 网络传输

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;int n;vector<vector<int> > g;vector<vector<int> > rg;vector<int> dfsOrder;int ncolor;int visited[110];vector<vector<int> > colorSet;int colorHash[110];void dfs(int v){visited[v] = 1;for (int i = 0; i < g[v].size(); i++){if (!visited[g[v][i]])dfs(g[v][i]);}dfsOrder.push_back(v);}void rdfs(int v, int k){colorSet[k].push_back(v);colorHash[v] = k;visited[v] = 1;for (int i = 0; i < rg[v].size(); i++){if (!visited[rg[v][i]])rdfs(rg[v][i], k);}}int main(){scanf("%d", &n);g.resize(n + 1);rg.resize(n + 1);int u;for (int i = 1; i <= n; i++){while (scanf("%d", &u) == 1 && u != 0){g[i].push_back(u);rg[u].push_back(i);}}memset(visited, 0, sizeof(visited));for (int i = 1; i <= n; i++){if (!visited[i])dfs(i);}ncolor = 0;memset(visited, 0, sizeof(visited));for (int i = dfsOrder.size() - 1; i >= 0; i--){if (!visited[dfsOrder[i]]){colorSet.push_back(vector<int>());rdfs(dfsOrder[i], ncolor++);}}int ans1 = 0;int startPoint = 0;for (int i = 0; i < colorSet.size(); i++){int tag = 1;for (int j = 0; j < colorSet[i].size(); j++){int u = colorSet[i][j];for (int k = 0; k < rg[u].size(); k++)//一个连通分支的一个点的边{if (colorHash[rg[u][k]] != i){tag = 0;break;}}}if (tag)ans1++;}int ans2 = 0;int endPoint = 0;for (int i = 0; i < colorSet.size(); i++)//每个连通分支{int tag = 0;for (int j = 0; j < colorSet[i].size(); j++)//每个连通分支的每个点{int u = colorSet[i][j];for (int k = 0; k < g[u].size(); k++)//一个连通分支的一个点的边{if (colorHash[g[u][k]] != i){tag = 1;break;}}if (tag == 1)break;}if (tag == 0){endPoint++;}}ans2 = max(ans1, endPoint);if (ncolor == 1){printf("%d\n", ans1);printf("%d\n", 0);}else{printf("%d\n", ans1);printf("%d\n", ans2);}}



tarjan 求割点和桥

#include <iostream>#include <vector>#include<algorithm>using namespace std;#define MAXN 200typedef vector<int> Edge;vector<Edge> G(MAXN);bool Visited[MAXN];int dfn[MAXN];int low[MAXN];int Father[MAXN]; //DFS树中每个点的父节点bool isCutVex[MAXN]; //每个点是不是割点int nTime; //Dfs时间戳int n, m; //n是点数, m是边数void Tarjan(int u, int father) //father 是u的父节点{Father[u] = father;int i, j, k;low[u] = dfn[u] = nTime++;for (i = 0; i < G[u].size(); i++){int v = G[u][i];if (!dfn[v]){Tarjan(v, u);low[u] = min(low[u], low[v]);}else if (father != v) //连到父节点的回边不考虑,否则求不出桥low[u] = min(low[u], dfn[v]);}}void Count(){ //计算割点和桥int nRootSons = 0; int i;Tarjan(1, 0);for (i = 2; i <= n; i++){int v = Father[i];if (v == 1)nRootSons++; //DFS树中根节点有几个子树else{if (dfn[v] <= low[i])isCutVex[v] = true;}}if (nRootSons > 1)isCutVex[1] = true;for (i = 1; i <= n; i++)if (isCutVex[i])cout << i << endl;for (i = 1; i <= n; i++){int v = Father[i];if (v > 0 && dfn[v] < low[i])cout << v << "," << i << endl;}}int main(){int u, v;int i;nTime = 1;cin >> n >> m; //n是点数, m是边数for (i = 1; i <= m; i++){cin >> u >> v; //点编号从1开始G[v].push_back(u);G[u].push_back(v);}memset(dfn, 0, sizeof(dfn));memset(Father, 0, sizeof(Father));memset(isCutVex, 0, sizeof(isCutVex));Count();return 0;}



tarjan 求双连通分量

#include <iostream>#include <vector>#include <queue>using namespace std;#define MAXN 200vector<vector<int> > G(MAXN);int dfn[MAXN];int low[MAXN];int nTime;int n, m; //n是点数, m是边数struct Edge{int u;int v;Edge(){}Edge(int u_, int v_) :u(u_), v(v_){}};deque<Edge> Edges;int nBlockNo = 0;void Tarjan(int u, int father){int i, j, k;low[u] = dfn[u] = nTime++;for (i = 0; i < G[u].size(); i++){int v = G[u][i];if (!dfn[v]){ //v没有访问过  //树边要入栈Edges.push_back(Edge(u, v));Tarjan(v, u);low[u] = min(low[u], low[v]);Edge tmp;if (dfn[u] <= low[v]){//从一条边往下走,走完后发现自己是割点,则栈中的边一定全是和自己在一个双连通分量里面//根节点总是和其下的某些点在同一个双连通分量里面cout << "Block No: " << ++nBlockNo << endl;do{tmp = Edges.back();Edges.pop_back();cout << tmp.u << "," << tmp.v << endl;} while (!(tmp.u == u &&tmp.v == v));}} // 对应if( ! dfn[v]) {else{if (v != father){//u连到父节点的回边不考虑low[u] = min(low[u], dfn[v]);if (dfn[u] > dfn[v])//连接到祖先的回边要入栈,但是连接到儿子的边,此处肯定已经入过栈了,不能再入栈Edges.push_back(Edge(u, v));}}} //对应 for( i = 0;i < G[u].size() ;i ++ ) {}int main(){int u, v;int i;nTime = 1;cin >> n >> m; //n是点数, m是边数nBlockNo = 0;for (i = 1; i <= m; i++){cin >> u >> v; //点编号从1开始G[v].push_back(u);G[u].push_back(v);}memset(dfn, 0, sizeof(dfn));Tarjan(1, 0);return 0;}



POJ 3352 道路重建


#include <vector>#include<algorithm>#include<string.h>#include<stdio.h>#include<stack>using namespace std;#define MAXN 1010typedef vector<int> Edge;vector<Edge> g(MAXN);int dfn[MAXN];int low[MAXN];int nTime; //Dfs时间戳int n, m; //n是点数, m是边数int degree[MAXN];stack<int> s;int colorHash[MAXN];int ncolor;void Tarjan(int u, int father) //father 是u的父节点{int i;s.push(u);low[u] = dfn[u] = nTime++;for (i = 0; i < g[u].size(); i++){int v = g[u][i];if (!dfn[v]){Tarjan(v, u);low[u] = min(low[u], low[v]);}else if (father != v) //连到父节点的回边不考虑,否则求不出桥low[u] = min(low[u], dfn[v]);}if (dfn[u] == low[u]){int temp;do{temp = s.top();s.pop();colorHash[temp] = ncolor;} while (!s.empty() && temp != u);ncolor++;}}void Count(){Tarjan(1, 0);for (int i = 1; i <= n; i++){for (int j = 0; j < g[i].size(); j++){int v = g[i][j];if (colorHash[i] != colorHash[v]){degree[colorHash[v]]++;degree[colorHash[i]]++;}}}int leaf = 0;for (int i = 0; i < ncolor; i++){if (degree[i] == 2)leaf++;}printf("%d\n", (leaf + 1) / 2);}int main(){while (scanf("%d%d", &n, &m) == 2) //n是点数, m是边数{int u, v;nTime = 1;memset(dfn, 0, sizeof(dfn));memset(degree, 0, sizeof(degree));for (int i = 0; i < MAXN; i++)g[i].clear();for (int i = 1; i <= m; i++){scanf("%d%d", &u, &v); //点编号从1开始g[v].push_back(u);g[u].push_back(v);}Count();}}



最短路




POJ 3159 糖果Dijkstra

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;struct Edge{int v;int w;Edge(){}Edge(int _v, int _w) :v(_v), w(_w){}};bool operator<(const Edge & lhs, const Edge & rhs){return lhs.w>rhs.w;}priority_queue<Edge> pq;bool isUsed[30010];vector<vector<Edge> > g;int n, m;int main(){scanf("%d%d", &n, &m);g.clear();g.resize(n + 1);memset(isUsed, 0, sizeof(isUsed));int a, b, c;for (int i = 1; i <= m; i++){scanf("%d%d%d", &a, &b, &c);g[a].push_back(Edge(b, c));}Edge e(1, 0);pq.push(e);while (!pq.empty()){e = pq.top();pq.pop();if (isUsed[e.v])continue;isUsed[e.v] = true;if (e.v == n){printf("%d\n", e.w);return 0;}for (int i = 0; i<g[e.v].size(); i++){if (isUsed[g[e.v][i].v])continue;pq.push(Edge(g[e.v][i].v, e.w + g[e.v][i].w));}}}


POJ 3259 Bellman-Ford 判断有无负权值回路

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;struct Edge{int u;int v;int w;Edge(){}Edge(int _u, int _v, int _w) :u(_u), v(_v), w(_w){}};vector<Edge> g;int n, m, w;bool Bellman_Ford(int v){vector<int> dist(n + 1);for (int i = 1; i <= n; i++)dist[i] = INF;dist[v] = 0;for (int i = 1; i<n; i++){int flag=0;for (int j = 0; j<g.size(); j++){int s = g[j].u;int e = g[j].v;if (dist[s] + g[j].w<dist[e]){dist[e] = dist[s] + g[j].w;flag=1;}}if(flag==0)return false;}for (int i = 0; i<g.size(); i++){int s = g[i].u;int e = g[i].v;if (dist[s] + g[i].w<dist[e])return true;}return false;}int main(){int t;scanf("%d", &t);while (t--){g.clear();scanf("%d%d%d", &n, &m, &w);int s, e, t;for (int i = 1; i <= m; i++){scanf("%d%d%d", &s, &e, &t);g.push_back(Edge(s, e, t));g.push_back(Edge(e, s, t));}for (int i = 1; i <= w; i++){scanf("%d%d%d", &s, &e, &t);g.push_back(Edge(s, e, -t));}if (Bellman_Ford(1))printf("YES\n");elseprintf("NO\n");}}



POJ 3259 SPFA 判断有无负权值回路

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;struct Edge{int v;int w;Edge(){}Edge(int _v, int _w) : v(_v), w(_w){}};vector<vector<Edge> >g;int n, m, w;bool spfa(int v){vector<int> vDist(n + 1);vector<int> updateTimes(n + 1);vector<bool> inqueue(n + 1);for (int i = 1; i <= n; i++){vDist[i] = INF;updateTimes[i] = 0;inqueue[i] = false;}vDist[v] = 0;queue<int> q;q.push(v);inqueue[v] = true;while (!q.empty()){int u = q.front();q.pop();inqueue[u] = false;for (int i = 0; i < g[u].size(); i++){int v = g[u][i].v;if (vDist[v] > vDist[u] + g[u][i].w){vDist[v] = vDist[u] + g[u][i].w;if (inqueue[v] == false){q.push(v);}++updateTimes[v];if (updateTimes[v] >= n)return true;}}}return false;}int main(){int t;scanf("%d", &t);while (t--){scanf("%d%d%d", &n, &m, &w);g.clear();g.resize(n + 1);int u, v, t;for (int i = 1; i <= m; i++){scanf("%d%d%d", &u, &v, &t);g[u].push_back(Edge(v, t));g[v].push_back(Edge(u, t));}for (int i = 1; i <= w; i++){scanf("%d%d%d", &u, &v, &t);g[u].push_back(Edge(v, -t));}if (spfa(1))printf("YES\n");elseprintf("NO\n");}}


POJ 3660 确定名次 弗洛伊德算法

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;int n, m;int g[110][110];int dist[110][110];int main(){scanf("%d%d", &n, &m);int a, b;memset(g, 0, sizeof(g));for (int i = 0; i < 110; i++)for (int j = 0; j < 110; j++){dist[i][j] = INF;}for (int i = 0; i < m; i++){scanf("%d%d", &a, &b);dist[a][b] = g[a][b] = 1;}for (int k = 1; k <= n; k++){for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]){dist[i][j] = dist[i][k] + dist[k][j];}}}}int ans = 0;for (int i = 1; i <= n; i++){int cnt = 0;for (int j = 1; j <= n; j++){if (dist[i][j] != INF || dist[j][i] != INF)cnt++;}if (cnt == n - 1)ans++;}printf("%d\n", ans);}



最小生成树



POJ 1258 kruskal模板


#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;struct Edge{int u, v, w;Edge(int _u, int _v, int _w) :u(_u), v(_v), w(_w){}Edge(){}bool operator<(const Edge & rhs)const{return w < rhs.w;}};vector<Edge> g;vector<int> parent;int n;int getParent(int a){if (parent[a] == a)return a;return parent[a] = getParent(parent[a]);}void merge(int a, int b){int p1 = getParent(a);int p2 = getParent(b);if (p1 == p2)return;parent[p2] = p1;}int main(){while (scanf("%d", &n) == 1){parent.clear();g.clear();for (int i = 0; i < n; i++)parent.push_back(i);for (int i = 0; i < n; i++)for (int j = 0; j < n; j++){int w;scanf("%d", &w);g.push_back(Edge(i, j, w));}sort(g.begin(), g.end());int done = 0;int totalLen = 0;for (int i = 0; i < g.size(); i++){if (getParent(g[i].u) != getParent(g[i].v)){merge(g[i].u, g[i].v);++done;totalLen += g[i].w;}if (done == n - 1)break;}printf("%d\n", totalLen);}}

POJ 1258 primHeap模板

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;struct Edge{int v, w;Edge(int _v = 0, int _w = INF) :v(_v), w(_w){}bool operator<(const Edge & e)const{return w > e.w;}};vector<vector<Edge> > g(110);int n;int heapPrim(){Edge xDist;priority_queue<Edge> pq;vector<int> vDist(n);vector<int> vUsed(n);int nDoneNum = 0;for (int i = 0; i < n; i++){vDist[i] = INF;vUsed[i] = 0;}int nTotalW = 0;pq.push(Edge(0, 0));while (nDoneNum < n && !pq.empty()){do{xDist = pq.top();pq.pop();} while (vUsed[xDist.v] == 1 && !pq.empty());if (vUsed[xDist.v] == 0){nTotalW += xDist.w;vUsed[xDist.v] = 1;nDoneNum++;for (int i = 0; i < g[xDist.v].size(); i++){int k = g[xDist.v][i].v;if (vUsed[k] == 0){int w = g[xDist.v][i].w;if (vDist[i] > w){vDist[i] = w;pq.push(Edge(k, w));}}}}}if (nDoneNum < n)return -1;return nTotalW;}int main(){while (scanf("%d", &n) == 1){for (int i = 0; i < n; i++)g[i].clear();for (int i = 0; i < n; i++)for (int j = 0; j < n; j++){int w;scanf("%d", &w);g[i].push_back(Edge(j, w));}printf("%d\n", heapPrim());}}


POJ 2349 村庄连接 double用%f

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;struct Edge{int u, v;double w;bool operator<(const Edge & rhs)const{return w < rhs.w;}};Edge g[1000010];int parent[550];int n, t, s;int getParent(int a){if (parent[a] == a)return a;return parent[a] = getParent(parent[a]);}void merge(int a, int b){int p1 = getParent(a);int p2 = getParent(b);if (p1 == p2)return;parent[p1] = p2;}int x[550], y[550];double ans[550];int main(){scanf("%d", &t);while (t--){scanf("%d%d", &s, &n);for (int i = 0; i < n; i++)parent[i] = i;int ncount = 0;for (int i = 0; i < n; i++){scanf("%d%d", &x[i], &y[i]);for (int j = 0; j < i; j++){double dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));g[ncount].u = i;g[ncount].v = j;g[ncount].w = dist;ncount++;}}sort(g, g + ncount);int done = 0;for (int i = 0; i < ncount; i++){if (getParent(g[i].u) != getParent(g[i].v)){merge(g[i].u, g[i].v);ans[done++] = g[i].w;if (done == n - s){printf("%.2f\n", g[i].w);break;}}}}}


UVA 1494 秦始皇修路


#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<queue>#include<ctype.h>#include<map>#include<math.h>using namespace std;const int INF = 1 << 30;struct Edge{int v;double w;Edge(){}Edge(int _v, double _w) :v(_v), w(_w){}bool operator<(const Edge & e)const{return w > e.w;}};double g[1010][1010];int n;double max_val[1010][1010];int x[1010];int y[1010];int p[1010];double heapPrim(){Edge xDist;priority_queue<Edge> pq;vector<double> vDist(n);vector<int> vUsed(n);vector<int> vLast(n);int nDoneNum = 0;for (int i = 0; i < n; i++){vDist[i] = INF;vUsed[i] = 0;vLast[i] = 0;}double nTotalW = 0;pq.push(Edge(0, 0));while (nDoneNum < n && !pq.empty()){do{xDist = pq.top();pq.pop();} while (vUsed[xDist.v] == 1 && !pq.empty());if (vUsed[xDist.v] == 0){nTotalW += xDist.w;vUsed[xDist.v] = 1;nDoneNum++;max_val[vLast[xDist.v]][xDist.v] = max_val[xDist.v][vLast[xDist.v]] = xDist.w;for (int i = 0; i < n; i++){if (vUsed[i] == 1 && i != vLast[xDist.v]){max_val[i][xDist.v] = max_val[xDist.v][i] = max(max_val[i][vLast[xDist.v]], max_val[vLast[xDist.v]][xDist.v]);}}for (int i = 0; i < n; i++){if (vUsed[i] == 0){double w = g[xDist.v][i];if (vDist[i] > w){vDist[i] = w;vLast[i] = xDist.v;pq.push(Edge(i, w));}}}}}if (nDoneNum < n)exit(1);return nTotalW;}int main(){int t;scanf("%d", &t);while (t--){scanf("%d", &n);for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)max_val[i][j] = -INF;for (int i = 0; i < n; i++){scanf("%d%d%d", &x[i], &y[i], &p[i]);for (int j = 0; j < i; j++){double dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));g[i][j] = g[j][i] = dist;}}double totalW = heapPrim();double ans = -INF;for (int i = 0; i < n; i++){for (int j = 0; j < i; j++){ans = max(ans, (p[i] + p[j]) / (totalW - max_val[i][j]));}}printf("%.2f\n", ans);}}


0 0