关于图论的一些小结 (一)
2012-10-22 08:19
288 查看
图论的主要算法:
1.图的广度优先遍历:
–先遍历较近的点,一层层向外扩展
–常用队列存储当前正被展开的点
伪代码:
一些应用:①无向图的连通分量
②网络流计算
例题:UVA 439 骑士游历
TOJ 1056树的直径
两次BFS
TOJ 2470 同一位置对应不同状态,vis[maxn][maxn][4]表示各个状态的BFS
对于不同的问题,应该明确到底具体每一步的状态究竟是什么
深度优先搜索DFS的伪代码
DFS遍历过程演示图
POJ 2817 TOJ 2281 Wordstack题目 比较经典的一道题目
既可以用暴力搜索进行解决(规模比较一般,但写起来比较麻烦)
也可以采用状态压缩的DP(方法相比于搜索复杂,但是代码很优美)
回顾集合运算:
判断j是否属于集合i:i&(1<<j)
在集合i中去除j:i-(1<<j)或者i&(!(1<<j)) i^(1<<j)
在集合i中加入点j:i|(1<<j);
先预处理出len[i][j]表示第i个字符串与第j个字符串组合能匹配的最大字符数,即如何摆放使得相邻的满足题意字符数目最多
好了,对于每一种字符选取状态,比如XXXXX5个字符串,对应2^5个选取状态,0表示没选中,1表示选中该字符串
dp[i][j]表示第i种状态下,以第j个字符串结尾所能达到的最大值
状态转移的公式为:
对于dp[i][j]而言,用标志k表示没选中的状态下标,然后尝试将第k个字符串加入到状态中,于是状态变为dp[i|(1<<k)][k]
dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k],dp[i][j]+len[j][k]);
关于状态压缩DP的更多信息:/article/8132735.html
1.图的广度优先遍历:
–先遍历较近的点,一层层向外扩展
–常用队列存储当前正被展开的点
伪代码:
Q={s}; 标记s为己访问; while (Q非空) { 取Q队首元素u; 所有与u相邻且未被访问的点进入队列; 标记u为已访问; }
一些应用:①无向图的连通分量
②网络流计算
例题:UVA 439 骑士游历
#include <iostream> #include <sstream> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <vector> #include <set> #include <cctype> #include <algorithm> #include <cmath> #include <deque> #include <queue> #include <map> #include <stack> #include <list> #include <iomanip> using namespace std; /// /// #define INF 0xffffff7 #define maxn 5060 /// char startx, starty, endx, endy; string pos1, pos2, tmp; int main() { /// int i, j, k; queue<string> poss; while (cin >> pos1 >> pos2) { while (!poss.empty()) poss.pop(); starty = pos1[1]; startx = pos1[0]; endy = pos2[1]; endx = pos2[0]; int cnt = 0; int hp = 0, tp = 1, lc = 1; poss.push(pos1); while (!poss.empty()) { tmp = poss.front(); poss.pop(); hp++; if (tmp == pos2) break; char nexty, nextx; //方向1 nexty = tmp[1] - 1; nextx = tmp[0] - 2; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向2 nexty = tmp[1] + 1; nextx = tmp[0] - 2; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向3 nexty = tmp[1] - 1; nextx = tmp[0] + 2; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向4 nexty = tmp[1] + 1; nextx = tmp[0] + 2; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向5 nexty = tmp[1] - 2; nextx = tmp[0] - 1; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向6 nexty = tmp[1] + 2; nextx = tmp[0] - 1; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向7 nexty = tmp[1] - 2; nextx = tmp[0] + 1; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } //方向8 nexty = tmp[1] + 2; nextx = tmp[0] + 1; if (nexty <= '8' && nexty >= '1' && nextx <= 'h' && nextx >= 'a') { string tempStr = ""; tempStr += nextx; tempStr += nexty; poss.push(tempStr); tp++; } if (hp == lc) { cnt++; lc = tp; } } cout << "To get from " << pos1 << " to " << pos2 << " takes " << cnt << " knight moves." << endl; } /// /// return 0; }
TOJ 1056树的直径
两次BFS
#include <iostream> #include <sstream> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <vector> #include <set> #include <cctype> #include <algorithm> #include <cmath> #include <deque> #include <queue> #include <map> #include <stack> #include <list> #include <iomanip> using namespace std; /// /// #define INF 0xffffff7 #define maxn 1050 /// int C, R; int nums = 0; char maze[maxn][maxn]; bool vis[maxn][maxn]; int startx, starty; struct pos{ int y; int x; }; int testcases; pos pos2; queue<pos> positons; int maxnum; void bfs(int starty, int startx) { pos tmppos, tmp; int cnt = 0; int hp = 0, tp = 1, lc = 1; tmppos.y = starty; tmppos.x = startx; vis[starty][startx] = true; positons.push(tmppos); while (!positons.empty()) { tmp = positons.front(); positons.pop(); hp++; int nexty, nextx; //方向1 nexty = tmp.y; nextx = tmp.x - 1; if (nexty < R && nexty >= 0 && nextx <= C && nextx >= 0 && vis[nexty][nextx] == false && maze[nexty][nextx] == '.') { pos pushpos; pushpos.y = nexty; pushpos.x = nextx; positons.push(pushpos); tp++; vis[nexty][nextx] = true; } //方向2 nexty = tmp.y - 1; nextx = tmp.x; if (nexty < R && nexty >= 0 && nextx <= C && nextx >= 0 && vis[nexty][nextx] == false && maze[nexty][nextx] == '.') { pos pushpos; pushpos.y = nexty; pushpos.x = nextx; positons.push(pushpos); tp++; vis[nexty][nextx] = true; } //方向3 nexty = tmp.y; nextx = tmp.x + 1; if (nexty < R && nexty >= 0 && nextx <= C && nextx >= 0 && vis[nexty][nextx] == false && maze[nexty][nextx] == '.') { pos pushpos; pushpos.y = nexty; pushpos.x = nextx; positons.push(pushpos); tp++; vis[nexty][nextx] = true; } //方向4 nexty = tmp.y + 1; nextx = tmp.x; if (nexty < R && nexty >= 0 && nextx <= C && nextx >= 0 && vis[nexty][nextx] == false && maze[nexty][nextx] == '.') { pos pushpos; pushpos.y = nexty; pushpos.x = nextx; positons.push(pushpos); tp++; vis[nexty][nextx] = true; } if (hp == lc) { cnt++; if (cnt > maxnum) { pos2 = tmp; maxnum = cnt; } lc = tp; } } } int main() { /// bool flag = true; int i, j, k; cin >> testcases; while (testcases--) { //清空队列,读入数据 memset(vis, false, sizeof(vis)); while (!positons.empty()) positons.pop(); cin >> C >> R; for (i = 0; i < R; i++) for (j = 0; j < C; j++) { cin >> maze[i][j]; if (maze[i][j] == '.') { if (flag) { starty = i; startx = j; flag = false; } } } //开始计算 maxnum = 0; bfs(starty, startx); memset(vis, false, sizeof(vis)); while (!positons.empty()) positons.pop(); bfs(pos2.y, pos2.x); cout << "Maximum rope length is " << maxnum - 1 << "." << endl; } /// /// return 0; }
TOJ 2470 同一位置对应不同状态,vis[maxn][maxn][4]表示各个状态的BFS
对于不同的问题,应该明确到底具体每一步的状态究竟是什么
#include <iostream> #include <sstream> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <vector> #include <set> #include <cctype> #include <algorithm> #include <cmath> #include <deque> #include <queue> #include <map> #include <stack> #include <list> #include <iomanip> using namespace std; /// /// #define INF 0xffffff7 #define maxn 105 /// int M, N; char maze[maxn][maxn]; int starty, startx, targety, targetx; int cnt; bool vis[maxn][maxn][4]; bool flag; struct robotState{ int posy; int posx; int dir; int steps; }; robotState finalState; queue<robotState> myWalking; void bfs() { int i, j; int hp = 0, tp = 1, lc = 1; robotState tmpState; tmpState.posy = starty; tmpState.posx = startx; tmpState.dir = 0; tmpState.steps = 0; vis[starty][startx][0] = true; myWalking.push(tmpState); while (!myWalking.empty()) { robotState tmp; tmp = myWalking.front(); myWalking.pop(); hp++; if (tmp.posy == targety && tmp.posx == targetx) { flag = true; finalState = tmp; break; } robotState nextState; //向前一步 if (tmp.dir == 0) { nextState.posy = tmp.posy - 1; nextState.posx = tmp.posx; nextState.dir = tmp.dir; nextState.steps = tmp.steps + 1; } else if (tmp.dir == 1) { nextState.posy = tmp.posy; nextState.posx = tmp.posx + 1; nextState.dir = tmp.dir; nextState.steps = tmp.steps + 1; } else if (tmp.dir == 2) { nextState.posy = tmp.posy + 1; nextState.posx = tmp.posx; nextState.dir = tmp.dir; nextState.steps = tmp.steps + 1; } else if (tmp.dir == 3) { nextState.posy = tmp.posy; nextState.posx = tmp.posx - 1; nextState.dir = tmp.dir; nextState.steps = tmp.steps + 1; } if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[nextState.posy][nextState.posx][nextState.dir] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[nextState.posy][nextState.posx][nextState.dir] = true; } //右转 nextState.posy = tmp.posy; nextState.posx = tmp.posx; nextState.dir = (tmp.dir + 1) % 4; nextState.steps = tmp.steps + 1; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[nextState.posy][nextState.posx][nextState.dir] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[nextState.posy][nextState.posx][nextState.dir] = true; } //左转 nextState.posy = tmp.posy; nextState.posx = tmp.posx; nextState.dir = (tmp.dir - 1 + 4) % 4; nextState.steps = tmp.steps + 1; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[nextState.posy][nextState.posx][nextState.dir] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[nextState.posy][nextState.posx][nextState.dir] = true; } /* //方向1 向北 nextState.posy = tmp.posy - 1; nextState.posx = tmp.posx; if (tmp.dir == 0) { nextState.steps = tmp.steps + 1; } else if (tmp.dir == 1 || tmp.steps == 3) { nextState.steps = tmp.steps + 2; } else if (tmp.dir == 2) { nextState.steps = tmp.steps + 3; } nextState.dir = 0; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[tmp.posy][tmp.posx][0] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[tmp.posy][tmp.posx][0] = true; } //方向2 向东 nextState.posy = tmp.posy; nextState.posx = tmp.posx + 1; if (tmp.dir == 1) { nextState.steps = tmp.steps + 1; } else if (tmp.dir == 0 || tmp.dir == 2) { nextState.steps = tmp.steps + 2; } else if (tmp.dir == 3) { nextState.steps = tmp.steps + 3; } nextState.dir = 1; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[tmp.posy][tmp.posx][1] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[tmp.posy][tmp.posx][1] = true; } //方向3 向南 nextState.posy = tmp.posy + 1; nextState.posx = tmp.posx; if (tmp.dir == 2) { nextState.steps = tmp.steps + 1; } else if (tmp.dir == 1 || tmp.dir == 3) { nextState.steps = tmp.steps + 2; } else if (tmp.dir == 0) { nextState.steps = tmp.steps + 3; } nextState.dir = 2; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[tmp.posy][tmp.posx][2] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[tmp.posy][tmp.posx][2] = true; } //方向4 向西 nextState.posy = tmp.posy; nextState.posx = tmp.posx - 1; if (tmp.dir == 3) { nextState.steps = tmp.steps + 1; } else if (tmp.dir == 0 || tmp.dir == 2) { nextState.steps = tmp.steps + 2; } else if (tmp.dir == 1) { nextState.steps = tmp.steps + 3; } nextState.dir = 3; if (nextState.posy >= 0 && nextState.posy < M && nextState.posx >= 0 && nextState.posx < N && vis[tmp.posy][tmp.posx][3] == false && maze[nextState.posy][nextState.posx] != '#') { myWalking.push(nextState); vis[tmp.posy][tmp.posx][3] = true; } */ } } int main() { /// int i, j, k; int testcases; cin >> testcases; while (testcases--) { //初始化 flag = false; cnt = 0; memset(vis, false, sizeof(vis)); while (!myWalking.empty()) myWalking.pop(); //读入数据 cin >> M >> N; for (i = 0; i < M; i++) { for (j = 0; j < N; j++) { cin >> maze[i][j]; if (maze[i][j] == 'S') { starty = i; startx = j; } if (maze[i][j] == 'T') { targety = i; targetx = j; } } } bfs(); if (flag) cout << finalState.steps << endl; else cout << -1 << endl; } /// return 0; }
深度优先搜索DFS的伪代码
dfs(int p) { timestamp = timestamp + 1; col[p] = GREY; d[p] = timestamp; for (每个与p相邻的点i) if (col[i] == WHITE) dfs(i); timestamp = timestamp + 1; f[p] = timestamp; col[p] = BLACK; }
DFS遍历过程演示图
POJ 2817 TOJ 2281 Wordstack题目 比较经典的一道题目
既可以用暴力搜索进行解决(规模比较一般,但写起来比较麻烦)
也可以采用状态压缩的DP(方法相比于搜索复杂,但是代码很优美)
回顾集合运算:
判断j是否属于集合i:i&(1<<j)
在集合i中去除j:i-(1<<j)或者i&(!(1<<j)) i^(1<<j)
在集合i中加入点j:i|(1<<j);
先预处理出len[i][j]表示第i个字符串与第j个字符串组合能匹配的最大字符数,即如何摆放使得相邻的满足题意字符数目最多
好了,对于每一种字符选取状态,比如XXXXX5个字符串,对应2^5个选取状态,0表示没选中,1表示选中该字符串
dp[i][j]表示第i种状态下,以第j个字符串结尾所能达到的最大值
状态转移的公式为:
对于dp[i][j]而言,用标志k表示没选中的状态下标,然后尝试将第k个字符串加入到状态中,于是状态变为dp[i|(1<<k)][k]
dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k],dp[i][j]+len[j][k]);
#include <iostream> #include <sstream> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <vector> #include <set> #include <cctype> #include <algorithm> #include <cmath> #include <deque> #include <queue> #include <map> #include <stack> #include <list> #include <iomanip> using namespace std; /// /// #define INF 0xffffff7 #define maxn 12 /// #define max(a,b)(a>b?a:b) int dp[1026][11]; int len[11][11]; int n; char str[11][11]; int main() { /// int n, i, j, k, x, count; int len1, len2, max; while(scanf("%d",&n),n) { memset(len, 0, sizeof(len)); for(i = 0; i < n; i++) scanf("%s", str[i]); //计算len[i][j] for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { if(i != j) { max = -1;//pay attention len1 = strlen(str[i]); len2 = strlen(str[j]); for(k = 0; k < len1; k++) { count = 0; for(x = 0; x<len2 && (x+k) < len1; x++) { if(str[i][x+k] == str[j][x]) count++; } if(count > max) max = count; } if(max > len[i][j]) len[i][j] = len[j][i] = max; } } } //自底向上计算 memset(dp, 0, sizeof(dp)); //对于i种状态而言 for(i = 0; i < (1<<n); i++) { for (k = 0; k < n; k++) { //如果第k个字符没有在状态中 if (!(i & 1 << k)) { //遍历该状态中不同字符结尾情况,然后将其加入到状态尾部,更新状态 for (j = 0; j < n; j++) { if (i & (1 << j)) dp[i|(1<<k)][k] = max( dp[i|(1<<k)][k], dp[i][j] + len[j][k]); } } } //j放在外面的写法 /* for(j = 0; j < n; j++) { if(i & (1 << j))//if j is in the set of i { for(k = 0; k < n; k++) { if(!(i & (1<<k)))//if k is not int the set of i,then process dp dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k],dp[i][j] + len[j][k]); } } } */ } max = -1; for( i = 0; i < (1<<n); i++) for(j = 0; j < n; j++) if(dp[i][j] > max) max = dp[i][j]; printf("%d\n", max); } /// return 0; }
关于状态压缩DP的更多信息:/article/8132735.html
相关文章推荐
- 关于图论的一些小结 (二)
- QT中关于QString的一些小结
- 关于Angularjs中自定义指令一些有价值的细节和技巧小结
- 关于一些图论的算法
- 关于 Angular2 学习的一些小结
- 关于近期学习java se篇的小结及一些学习路线的思考
- 【转】关于 PHP Session 的 Time out 和有效设置 Session 时间限制的一些小结
- 关于Intelli IDEA的一些快捷方式小结
- 关于Quartus和ISE中ROM的初始化和仿真的一些小结
- 【java之路】关于oracle数据库的一些操作小结(一)
- 关于项目中使用的关于nio client的一些小结
- 关于位操作的一些技巧小结
- 关于 .net 开发 Office Word 的一些问题小结
- 关于 css html 的一些小结
- 关于php的一些小结
- 关于性能测试的一些个人小结
- 关于近期HBase系统设计开发和性能调优的一些小结
- javascript中关于类型判断的一些疑惑小结
- 关于asp.net ajax的一些小结
- C#使用HttpWebRequest进行HTTP请求发送和接收的一些小结。(新增修复.NET4.0以下关于cookie的bug)