11.1.1 无根树转有根树
c
#include
#include #include using namespace std; #define MAXN 10000 vector G[MAXN]; int n; int p[MAXN]; void read_tree() { int u, v; scanf("%d", &n); for(int i = 0; i < n-1; i++) { scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } } void dfs(int u, int fa) { int d = G[u].size(); for(int i = 0; i < d; i++) { int v = G[u][i]; if(v != fa) dfs(v, p[v] = u); } } void debug_array(int a[], int len) { for(int i = 0; i < len ;i++) cout << a[i] << " "; cout << endl; } int main() { freopen("input", "r", stdin); read_tree(); int root; scanf("%d", &root); p[root] = -1; dfs(root, -1); debug_array(p, n); return 0; }
11.1.2 表达式树
c
#include
#include #include using namespace std; const int maxn = 1000; int lch[maxn], rch[maxn]; char op[maxn]; int nc = 0; // 节点个数 int build_tree(char *s, int x, int y) { int i, c1 = -1, c2 = -1, p=0; int u; if(y-x == 1) { u = ++nc; lch[u] = rch[u] = 0; op[u] = s[x]; return u; } for(i = x; i < y; i++) { switch(s[i]) { case '(': p++; break; case ')': p--; break; case '-': case '+': if(!p) c1 = i; break; case '/': case '*': if(!p) c2 = i; break; } } if(c1 < 0) c1 = c2; if(c1 < 0) return build_tree(s, x+1, y-1); u = ++nc; lch[u] = build_tree(s, x, c1); rch[u] = build_tree(s, c1+1, y); op[u] = s[c1]; return u; } // simple test but not right void dfs(int root) { if(root == 0) return; dfs(lch[root]); printf("%c", op[root]); dfs(rch[root]); } int main() { freopen("input", "r", stdin); char s[maxn]; scanf("%s", s); int len = strlen(s); // printf("%d\n", len); int root = build_tree(s, 0, len); dfs(root); return 0; }
11.1.3 最小生成树kruskals算法
c
const int maxn = 1000; int p[maxn]; // 初始化并查集 int w[maxn]; // 边的权重 int r[maxn]; // 边的序号 int u[maxn]; // 边序号对应那个点 int v[maxn]; int cmp(const int i, const int j){ return w[i] < w[j]; } int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } int kruskal() { int n, m; int ans = 0; for(int i = 0; i < n; i++) p[i] = i; // 初始化并查集 for(int i = 0; i < m; i++) r[i] = i; // 初始化边序号 sort(r, r+m, cmp); // 给边排序 for(int i = 0; i < m; i++) { // 找出当前边两个端点所在的集合编号 int e = r[i]; int x = find(u[e]); int y = find(v[e]); // 在不同的集合,合并 if(x != y) { ans += w[e]; p[x] = y;} } return ans; }
11.2.1 Dijkstra 算法(最短路径)
c
#include
#include #include #include #include using namespace std; // struct cmp { bool operator() (const int a, const int b) { return a % 10 > b % 10; } }; priority_queue , cmp > que; typedef pair pii; priority_queue , greater > q; const int MAXN = 1000; const int MAXM = 1000; const int INF = 0x3f3f3f3f; int d[MAXM], w[MAXM], next[MAXM], first[MAXM], v[MAXM]; void dijkstra(int n) { bool done[MAXN]; for(int i = 0; i < n; i++) d[i] = (i == 0? 0 : INF); memset(done, 0, sizeof(done)); q.push(make_pair(d[0], 0)); while(!q.empty()) { pii u = q.top(); q.pop(); int x = u.second; if(done[x]) continue; done[x] = true; for(int e = first[x]; e != -1; e = next[e]) if(d[v[e]] > d[x] + w[e]) { d[v[e]] = d[x] + w[e]; q.push(make_pair(d[v[e]], v[e])); } } }
11.2.4 Bellman-Ford 算法(负权最短路径)
当负权存在的时候,如果最短路径存在,通过Bellman算法可以求出
c
// 存在权重为负的时候,最短路径不一定存在。 const int MAXM = 1000; int first[MAXM], next[MAXM], v[MAXM], d[MAXM], w[MAXM]; void bellman() { const int MAXN = 1000; // 最大点数 queue
q; bool inq[MAXN]; memset(inq, 0, sizeof(inq)); // 在队列中的标志 q.push(0); while(!q.empty()) { int x = q.front(); q.pop(); inq[x] = false; for(int e = first[x]; e != -1; e = next[e]) if(d[v[e]] > d[x] + w[e]) { d[v[e]] = d[x] + w[e]; if(!inq[v[e]]) { inq[v[e]] = true; q.push(v[e]); } } } }
11.2.5 Floyd 算法(两点最短路径)
如果n>300就不要使用了
c
for(int k = 0; k < n ;k++) for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) if(d[i][j] > d[i][k] + d[k][j]) d[i][j] = d[i][k] + d[k][j];