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

图论的主要算法:

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的更多信息:http://blog.csdn.net/accry/article/details/6607703

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值