例题7-1
没有测试数据,暂且掠过。
例题7-2
卓麻烦,尝试着写了一下,应该自己手写一个队列来实现,用以输出各个整数。
要实现一个分数的struct。
没有写完。
cpp
#include <stdio.h> #include <iostream> using namespace std; const int maxn = 1000; struct num { int parent, child; int cur; num() {} num(int _p, int _c) { parent = _p; child = _c; } void reduction() { int t = gcd(parent, child); parent /= t; child /= t; } int gcd(int a, int b) { if(a % b == 0) return b; else return gcd(b, a % b); } num operator - (const num a) const { num temp; temp.child = a.child * parent + a.parent * child; temp.parent = a.parent * parent; temp.reduction(); return temp; } num operator = (num a) { parent = a.parent; child = a.child; } bool operator == (int a) { return child == a; } num operator * (int a) { num b; b.child = child * a; b.parent = parent; b.reduction(); return b; } }; int a, b; int nb[maxn]; struct node { node *pre; num val; node(){} node(num b) { val = b; } node(node a, num b) { pre = &a; val = b; } node operator = (num a) { val = a; return *this; } }; void output(node a) {} int suc[maxn]; int found; void bfs() { int cur = 2; node q[maxn]; int front, rear; front = rear = 0; // 成功队列 int suc[maxn]; int cnt = 0; num s = num(a, b); s.cur ++; node ss = s; q[front++] = ss; bool ac = false; while(front != rear) { num b = q[front].val; if(b.cur > cur) { // 增加深度上限 if(!ac) cur++; else break; } // 确定增加数的范围 // int n = b.cal(); int n = 100; for(int i = b.parent+1; i < n; i++) { num temp = b - num(1, i); temp.cur = b.cur+1; if(temp == 0) { ac = true; // suc.push(b-num(1,i)); suc[cnt++] = front; } else { // q.push(num(1, i)); q[rear++] = node(q[front], num(1,i)); } } front--; } if(cnt == 1) output(q[suc[cnt-1]]); else { // compare int i = 0; output(q[suc[i]]); } } int main(int argc, const char *argv[]) { while(~scanf("%d%d", a, b)) { } return 0; }
7.3 倒水问题
书上的状态问题不错 -- 但问题是如何确定是否返回之前的状态。
如果使用vis存储,那么:
1. 因为水量不变,所以状态的总数最多为`(b+1)(c+1)`,也就是$10^6$,可以承受了。
2. 一个节点最多有6种指向其他状态的边,所以最多的边数是$6*10^6$
如果担心存不下,可以参照八数码的三种解决方法。
7.5.3 八数码
一共有三种判重的方法:
- 编码解码
- 自己写hash,建立hash函数
- 使用STL
c
#include <stdio.h> #include <iostream> #include <string.h> #include <set> using namespace std; typedef int State[9]; const int MAXSTATE = 1000000; State st[MAXSTATE], goal; int dist[MAXSTATE]; const int dx[] = {-1, 1, 0, 0}; const int dy[] = {0, 0, -1, 1}; // 3 option // 1. encoding & decoding namespace coding { int vis[362888], fact[9]; void init_lookup_table() { fact[0] = 1; // fact = {1, 2, 6, ...} // 位置不同weight不同 for(int i = 1; i < 9; i++) fact[i] = fact[i-1] * i; } int try_to_insert(int s) { int code = 0; for(int i = 0; i < 9; i++) { // 求编码 // 倘若后面的数字大于前面的数字,cnt++ int cnt = 0; for(int j = i+1; j < 9; j++) if(st[s][j] > st[s][i]) cnt++; code += fact[8-i] * cnt; } if(vis[code]) return 0; return vis[code] = 1; } }; //2. hash namespace hash{ const int MAXHASHSIZE = 1000003; int head[MAXHASHSIZE], next[MAXSTATE]; void init_lookup_table() { memset(head, 0, sizeof(head)); } int hash(State &s) { int v = 0; for(int i = 0; i < 9; i++) v = v * 10 + s[i]; return v % MAXHASHSIZE; } int try_to_insert(int s) { int h = hash(st[s]); int u = head[h]; while(u) { if(memcmp(st[u], st[s], sizeof(st[s]) == 0)) return 0; u = next[u]; } next[s] = head[h]; head[h] = s; return 1; } }; //3. STL 的方法 namespace STL_set{ set <int> vis; void init_lookup_table() { vis.clear();} int try_to_insert(int s) { int v = 0; for(int i = 0; i < 9; i++) v = v * 10 + st[s][i]; if(vis.count(v)) return 0; vis.insert(v); return 1; } }; // 速度较慢 namespace STL_set_struct { struct cmp { bool operator () (int a, int b) const { return memcmp(&st[a], &st[b], sizeof(st[b])) < 0; } }; set <int, cmp> vis; void init_lookup_table() { vis.clear();} int try_to_insert(int s) { if(vis.count(s)) return 0; vis.insert(s); return 1; } }; using namespace STL_set_struct; int bfs() { init_lookup_table(); int front = 1, rear = 2; while(front < rear) { State &s = st[front]; if(memcmp(goal, s, sizeof(s)) == 0) return front; int z; for(z = 0; z < 9; z++) if(!s[z]) break; int x = z/3, y = z % 3; for(int d = 0; d < 4; d++) { // 计算新数的位置 int newx = x + dx[d]; int newy = y + dy[d]; int newz = newx * 3 + newy; if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3) { State &t = st[rear]; memcpy(&t, &s, sizeof(s)); // 交换两个格子 t[newz] = s[z]; t[z] = s[newz]; dist[rear] = dist[front] + 1; if(try_to_insert(rear)) rear++; } } // 弹出 front++; } return 0; } int main(int argc, const char *argv[]) { freopen("input", "r", stdin); for(int i = 0 ; i < 9 ; i++) scanf("%d", &st[1][i]); for(int i = 0; i < 9; i++) scanf("%d", &goal[i]); int ans = bfs(); if(ans > 0) printf("%d\n", dist[ans]); else puts("-1"); return 0; }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。