题目描述
题目解析
这道题是算法:机器人必须走 K 步,最终能来到P位置的方法有多少种的升级版
思路: 先生成一个图,然后递归求解
struct Node;
struct Edge;
struct Graph;
struct Node{
int val;
int in;
int out;
std::vector<std::shared_ptr<Node>> nexts;
std::vector<std::shared_ptr<Edge>> edges;
explicit Node(int val, int in = 0, int out = 0) : val(val), in(0), out(0){
}
};
struct Edge{
int weight;
std::shared_ptr<Node> from;
std::shared_ptr<Node> to;
explicit Edge(int w, std::shared_ptr<Node>&f, std::shared_ptr<Node>& t) : weight(w), from(f), to(t) {
}
};
struct Graph{
std::map<int, std::shared_ptr<Node>> nodes;
std::set<std::shared_ptr<Edge>> edges;
};
class Solution {
static std::shared_ptr<Graph> createGraph(vector<vector<int>>& relation){
std::shared_ptr<Graph> graph = std::make_shared<Graph>();
int N = relation.size();
for (int i = 0; i < N; ++i) {
int fromLabel = relation[i][0], toLabel = relation[i][1];
if(!graph->nodes.count(fromLabel)){
graph->nodes[fromLabel] = std::make_shared<Node>(fromLabel);
}
if(!graph->nodes.count(toLabel)){
graph->nodes[toLabel] = std::make_shared<Node>(toLabel);
}
auto fromNode = graph->nodes[fromLabel], toNode = graph->nodes[toLabel];
std::shared_ptr<Edge> newEdge = std::make_shared<Edge>(0, fromNode, toNode);
fromNode->out++;
toNode->in--;
fromNode->nexts.emplace_back(toNode);
fromNode->edges.emplace_back(newEdge);
graph->edges.emplace(newEdge);
}
return graph;
}
int walkPath(std::shared_ptr<Node> &start, std::shared_ptr<Node> &end, int k){
if(k == 0){
return start == end ? 1 : 0;
}
int ways = 0;
for(auto node : start->nexts){
ways += walkPath(node, end, k - 1);
}
return ways;
}
public:
int numWays(int n, vector<vector<int>>& relation, int k) {
if(relation.empty() || k < 0){
return 0;
}
std::shared_ptr<Graph> graph = createGraph(relation);
std::shared_ptr<Node> start = graph->nodes[0];
std::shared_ptr<Node> end = graph->nodes[n - 1];
if(start == nullptr || end == nullptr){
return 0;
}
return walkPath(start, end, k);
}
};
备忘录
#include <vector>
#include <map>
#include <vector>
#include <memory>
#include <stack>
#include <set>
#include <queue>
#include <iostream>
using namespace std;
struct Node;
struct Edge;
struct Graph;
struct Node{
int val;
int in;
int out;
std::vector<std::shared_ptr<Node>> nexts;
std::vector<std::shared_ptr<Edge>> edges;
explicit Node(int val, int in = 0, int out = 0) : val(val), in(0), out(0){
}
};
struct Edge{
int weight;
std::shared_ptr<Node> from;
std::shared_ptr<Node> to;
explicit Edge(int w, std::shared_ptr<Node>&f, std::shared_ptr<Node>& t) : weight(w), from(f), to(t) {
}
};
struct Graph{
std::map<int, std::shared_ptr<Node>> nodes;
std::set<std::shared_ptr<Edge>> edges;
};
class Solution {
static std::shared_ptr<Graph> createGraph(vector<vector<int>>& relation){
std::shared_ptr<Graph> graph = std::make_shared<Graph>();
int N = relation.size();
for (int i = 0; i < N; ++i) {
int fromLabel = relation[i][0], toLabel = relation[i][1];
if(!graph->nodes.count(fromLabel)){
graph->nodes[fromLabel] = std::make_shared<Node>(fromLabel);
}
if(!graph->nodes.count(toLabel)){
graph->nodes[toLabel] = std::make_shared<Node>(toLabel);
}
auto fromNode = graph->nodes[fromLabel], toNode = graph->nodes[toLabel];
std::shared_ptr<Edge> newEdge = std::make_shared<Edge>(0, fromNode, toNode);
fromNode->out++;
toNode->in--;
fromNode->nexts.emplace_back(toNode);
fromNode->edges.emplace_back(newEdge);
graph->edges.emplace(newEdge);
}
return graph;
}
std::map<std::string, int> map;
int walkPath(std::shared_ptr<Node> &start, std::shared_ptr<Node> &end, int k){
std::string key = std::to_string(start->val) + "_" + std::to_string(end->val) + "_" + std::to_string(k);
if(map.count(key)){
return map[key];
}
int ways = 0;
if(k == 0){
ways = start == end ? 1 : 0;
}else{
for(auto node : start->nexts){
ways += walkPath(node, end, k - 1);
}
}
map[key] = ways;
return ways;
}
public:
int numWays(int n, vector<vector<int>>& relation, int k) {
if(relation.empty() || k < 0){
return 0;
}
std::shared_ptr<Graph> graph = createGraph(relation);
std::shared_ptr<Node> start = graph->nodes[0];
std::shared_ptr<Node> end = graph->nodes[n - 1];
if(start == nullptr || end == nullptr){
return 0;
}
return walkPath(start, end, k);
}
};
暴力递归改动态规划
(1)准备表,主要通过分析可变参数的取值范围得到
int walkPath(std::shared_ptr<Node> &start, std::shared_ptr<Node> &end, int k)
- start:取值范围----
start--end
-----0---n - 1
- k:取值范围------
0~k
所以准备一个二维数组:
std::vector<std::vector<int>> dp[n][k + 1];
(2)分析返回值,主要看主函数是怎么调用
return walkPath(start, end, k); // walkPath(0, n - 1, k);
所以应该返回dp[0][k]
(3)开始填表
(3.1)base case,也就是表初始化
if(k == 0){
return start == end ? 1 : 0;
}
- 从上面可以看出,需要填写k = 0时
dp[0][0] = 1; // 开始位置为0,而且不需要走路
(3.2)分析普通情况
- 先看依赖
for(auto node : start->nexts){
ways += walkPath(node, end, k - 1);
}
- 从上面可以看出:
待续…