思路:
题目的主要信息:
- 一个N个城市,A数组中记录的是访问每个城市所需的花费,V是初始所有的总预算
- 如果同时访问了两个城市,需要满足List中Point记录的先后顺序
- 求满足预算条件下,最多访问的城市数
方法一:暴力法(超时)
具体做法:
利用next_permutation函数对1-N个城市进行全排列,然后检查这种排列是否符合预算与访问顺序。访问顺序可以用一个二维vector保存,一维是后访问的城市,二维是其前序访问城市。
class Solution {
public:
int Travel(int N, int V, vector<int>& A, vector<Point>& List) {
int res = 0;
vector<vector<int> > city(N + 1);
vector<int> B(N + 1);
for(int i = 0; i < List.size(); i++)
city[List[i].y].push_back(List[i].x); //记录城市的先后顺序
for(int i = 1; i <= N; i++)
B[i] = i; //排列组合
do{
int sum = 0;
int rest = V; //剩余的钱
vector<bool> flag(N + 1, false); //记录访问过的记录
for(int i = 1; i <= N; i++){
for(int j = 0; j < city[B[i]].size(); j++)
if(!flag[city[B[i]][j]]) //访问顺序中已经访问过了
break;
if(rest >= A[B[i] - 1]){ //可以继续访问
sum++;
rest -= A[B[i] - 1];
}else
break;
flag[B[i]] = true;
}
res = max(res, sum);
}while(next_permutation(B.begin() + 1, B.end())); //全排列
return res;
}
};复杂度分析:
- 时间复杂度:
,全排列为
,里面是两层循环
- 空间复杂度:
,辅助数组city最坏情况是
的二维辅助矩阵
方法二:递归+空间记忆
具体做法:
我们可以对种状态利用二进制掩码形式逐一对其递归进行搜索,每次查看经费和前后续关系。搜索函数中
为当前的状态数,
为当前最大这段序列可访问的最大城市数,递归的时候减小经费
,改变
与
即可进入子问题。为了防止递归处理的问题太大,我们可以用数组dp记录所有的前面计算过的序列的可访问的最大值。
class Solution {
public:
int search(vector<vector<int> >& city, vector<int>& dp, vector<int>& A, int N, int V, int m, int n){
if(dp[m] != 0)
return dp[m];
int maxn = n;
for(int i = 0; i < N; i++){
if(((1 << i) & m) > 0 || A[i] > V) // 如果当前 节点已经走过或者费用不足,就不需要进行搜索
continue;
bool flag = true;
for(int j = 0; j < city[i].size(); j++){ //查看它的前驱节点是否走过
if(((1 << city[i][j]) & m) == 0){
flag = false;
break;
}
}
if(flag) //找到最大值
maxn = max(maxn, search(city, dp, A, N, V-A[i], m ^ (1 << i), n + 1));
}
dp[m] = maxn; //记忆避免多次递归
return dp[m];
}
int Travel(int N, int V, vector<int>& A, vector<Point>& List) {
vector<int> dp(1 << N, 0); //一共2^N个状态
vector<vector<int> > city(N, vector<int>()); //记录城市的先后顺序
for(int i = 0; i < List.size(); i++)
city[List[i].y - 1].push_back(List[i].x - 1);
return search(city, dp, A, N, V, 0, 0);
}
};复杂度分析:
- 时间复杂度:
,一共
个状态,递归中需要循环的部分其实只有dp数组的大小,其他的都是直接返回
- 空间复杂度:
,其中dp长度为为
,city最坏为

京公网安备 11010502036488号