[算法机试模拟题]1007.小黄车

【问题描述】

随着共享经济的兴起,大学城如今到处可见ofo小黄车. 小左现在打算每天都骑小黄车从宿舍去实验室. 假设大学城的地图可以简化为一个有向图,图中有N个地点(节点),用0到N-1进行编号,有些地点之间存在有向的道路(有向边). 小左的宿舍所在地点编号为0,实验室所在地点编号为N-1. 小左希望为连续的M天规划线路,使得每天从宿舍到实验室,都至少会经过一条之前没有走过的道路(有向边). 小左想知道M的最大值,你能帮助他么?
 
请实现下面Solution类中的countPath函数,完成上述功能.
参数G: N*N(2 <= N <= 50)邻接矩阵,如果地点i到地点j之间有道路,则G[i][j] = 1;否则G[i][j] = 0. G[i][i]的值总是为0.
返回值:M的最大值. 如果不存在满足要求的路径则返回0.
 
class Solution {
public:
int countPaths(vector<vector<int>> G) {
}          
};
 
例1:
G = {{0, 1}, {1, 0}},返回值为2,因为第1天:0 --> 1,第2天 0 --> 1 --> 0 --> 1. 虽然小左第2天兜了一下圈,但他确实走了一条第1天没有走过的边1 --> 0.
 
例2:
G = {{0, 1, 1}, {1, 0, 1}, {1, 0, 0}},返回值为4.
第1天:0 --> 2
第2天:0 --> 2 --> 0 --> 2
第3天:0 --> 1 --> 2
第4天:0 --> 1 --> 0 --> 1 --> 2
 
例3:
G = {{0, 1, 0}, {1, 0, 0}, {0, 0, 0}},返回值为0.

【解题分析】

有n个顶点的一个图,求从节点0到节点n-1的路径最大数,其中每条路径必须包含一条以前没有走过的边。

我们可以这样考虑,先删除所有不能从节点0到达的节点以及该节点所关联的边,因为节点0不能到达,对于我们的结果是没有任何影响的;其次,删除所有不能到达节点n-1节点的节点以及关联的边,这对于我们的结果也没有影响。删除这些节点和边形成了一个新图,其大小为m个节点,k条边。

最后,我们每经过一个节点必须“消耗”两条边,也即是一条入边,一条出边,但我们的起点和终点边是不需要的,也即是m-2个节点;于是我们能得到(k-(m-2))条路径。

举例:
1、0.....v.....n-1,v是原来没经过的节点,我们可以说是一个节点抵消了一条边,得到了一条路径;
2、0.....v...u.....n-1,v和u是原来没经过的节点,我们可以说是两个节点抵消了两条边,得到了一条路径;
3、0.....v...u....n-1,v和u之间有原来没走过的边,一条边得到了一条路径。

【源代码】

class Solution {
public:
	int countPaths(vector<vector<int> > G) {
		int result = 0;
		int m = G.size();
		int n = G[0].size();
		if (m < 2 || n < 2 || n > 50 || m > 50)	return 0;
		// 该点是否被遍历
		vector<bool> vis(m,0);
		
		// 该点是否能到终点 
		vector<bool> to_des(n,0);
		queue<int> visited;
		
		// 删除起点不能到达的点 
		visited.push(0);
		vis[0] = true;
		while(!visited.empty()) {
			int t = visited.front();
			visited.pop();
			for (int i = 0; i < m; i++) {
				if(G[t][i] == 1 && !vis[i] && t != i) {
					vis[i] = true;
					visited.push(i);
				}
			}
		}
		if (!vis[n-1])	return 0;
		
		// 删除不能到达终点的点 
		visited.push(n-1);
		to_des[n-1] = true;
		while(!visited.empty()) {
			int t = visited.front();
			visited.pop();
			for (int i = 0; i < m; i++) {
				if (G[i][t] == 1 && !to_des[i] && i != t) {
					to_des[i] = true;
					visited.push(i);
				}
			}
		}
		
		//计算剩余的边 
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (G[i][j] == 1 && vis[i] && vis[j] && to_des[i] && to_des[j]) {
					result++;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			if (to_des[i] && vis[i]) {
				result--;
			}
		}
		return result+2;
	}
};
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值