您的位置:首页 > 其它

关于图论的一些小结 (一)

2012-10-22 08:19 288 查看
图论的主要算法:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: