Bootstrap

算法测验第二次

***************************************************************************************************************
[算法课回溯]组合问题
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你需要按顺序返回答案。
#include<bits/stdc++.h>
using namespace std;
int n,k;

void dfs(vector<vector<int> >& res,vector<int>& v,int cnt){
	if(v.size()==k){
		res.push_back(v);
	}
	for(int i=cnt;i<=n&&v.size()<k;i++){	
		v.push_back(i);
		dfs(res,v,i+1);
		v.pop_back();
		
	}
	return;
}

int main(){
	cin>>n>>k;
	vector<vector<int> > res;
	vector<int> v;
	dfs(res,v,1);
	cout<<"[";
	for(int j=0;j<res.size();j++){
		cout<<"[";
		for(int i=0;i<k;i++){
			cout<<res[j][i];
			if(i<k-1){
				cout<<", ";
			}
		}
		if(j<res.size()-1){
			cout<<"], ";	
		}else{
			cout<<"]";
		}
	}
	cout<<"]";	
	return 0;
} 


******************************************************************************************************************
[算法课回溯]找出所有子集的异或总和再求和
一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0#include<bits/stdc++.h>
using namespace std;

int main(){
	vector<int> v;
	int x;
	while(cin>>x){
		v.push_back(x);
	}
	int n=v.size();
	if(n==0){
		return 0;
	}
	int sum=0;
    for(int i=0;i<(1<<n);i++){
        int tmp=0;
        for(int j=0;j<n;j++){
            if((i&(1<<j))>0){
                tmp ^= v[j];
            }
        }
        sum+=tmp;
    }
	cout<<sum<<endl;
	return 0;
} 

******************************************************************************************************************
 [算法课回溯]分割回文串
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
#include<bits/stdc++.h>
using namespace std;
vector<vector<string>> res;
vector<string> ans;

void dfs(string &s,vector<vector<int>> f,int i,int n){
	if(i==n){
		res.push_back(ans);
		return;
	}
	for(int j=i;j<n;j++){
		if(f[i][j]){
			ans.push_back(s.substr(i,j-i+1));
			dfs(s,f,j+1,n);
			ans.pop_back();
		}
	}
	
}
int main(){
	string s;
	cin>>s;
	int n=s.size();
	vector<vector<int>> f(n,vector<int>(n,true)); 
	for(int i=n-1;i>=0;i--){
		for(int j=i+1;j<n;j++){
			f[i][j] = (s[i]==s[j]) && (f[i+1][j-1]);
		}
	}
	dfs(s,f,0,n);
	cout<<"[";
	for(int i=0;i<res.size();i++){
		cout<<"[";
		for(int j=0;j<res[i].size();j++){
			cout<<res[i][j];
			if(j!=res[i].size()-1){
				cout<<", ";
			} 
		}
		cout<<"]";
		if(i!=res.size()-1){
			cout<<", ";
		}
	}
	cout<<"]";
	return 0;
} 
******************************************************************************************************************
Problem P16. [算法课回溯]目标和
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式 :

#include<bits/stdc++.h>
using namespace std;
vector<int> nums;
int target=0;
int cnt=0;
void dfs(int target,int i){
	if(target==0&&i==nums.size()){
		cnt++;
		return;
	}
	if(i==nums.size()){
		return;
	}
	dfs(target-nums[i],i+1);
	dfs(target+nums[i],i+1);
}

int main(){
	int x;
	while(cin>>x){
		nums.push_back(x);
	}
	nums.pop_back();
	target=x;
	dfs(target,0);
	cout<<cnt<<endl;
	return 0;
}

******************************************************************************************************************
Problem P17. [算法课分支限界法]组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

#include<bits/stdc++.h>
using namespace std;
vector<int> v;
int n,k;

void dfs(int start,int cnt){
	if(cnt==k){
		for(int i=0;i<v.size();i++){
			cout<<v[i]<<' ';
		}
		cout<<endl;
		return;
	}
	
	for(int i=start;i<=n;i++){
		v.push_back(i);
		dfs(i+1,cnt+1);
		v.pop_back();
	}
	
}

int main(){
	cin>>n>>k;
	dfs(1,0);

	return 0;
}
******************************************************************************************************************
Problem P18. [算法课分支限界法]大礼包
在商店中, 有 n 件在售的物品。每件物品都有对应的价格。然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。

#include<bits/stdc++.h>
using namespace std;
int cost = -1;

void backtrack(vector<int>& price, vector<vector<int>>& special, vector<int>& needs, int idx, int sum) {
    if (idx == special.size()) {
        if (cost != -1) {
            cost = min(cost, sum);
        } else {
            cost = sum;
        }
        return;
    }
    bool flag = true;
    int k = 0;
    backtrack(price, special, needs, idx+1, sum);
    while (flag) {
        int j = 0;
        for (j = 0; j < needs.size(); j++) {
            needs[j] -= special[idx][j];
            if (needs[j] < 0) {
                break;
            }
            sum -= special[idx][j]*price[j];
            // cout << idx << " " << j << " " << sum << endl;
        }
        if (j == needs.size()) {
            sum += special[idx][needs.size()];
            backtrack(price, special, needs, idx+1, sum);
            k++;
            continue;
        }
        for (; j >= 0; j--) {
            needs[j] += special[idx][j];
        }
        flag = false;
    }
    for (int j = 0; j < needs.size(); j++) {
        needs[j] += k*special[idx][j];
    }
}
int main(){
	vector<int> price, needs;
    vector<vector<int>> special;
    int d;
    while (cin >> d) {
        price.push_back(d);
        if (getchar() == '\n') {
            break;
        }
    }
    int n = price.back();
    price.pop_back();
	for (int i = 0; i < n; i++) {
        vector<int> arr;
        while (cin >> d) {
            arr.push_back(d);
            if (getchar() == '\n') {
                break;
            }
        }
        special.emplace_back(arr);
    }
    while (cin >> d) {
        needs.push_back(d);
        if (getchar() == '\n') {
            break;
        }
    }
    int sum = 0;
    for (int i = 0; i < price.size(); i++) {
        sum += price[i]*needs[i];
    }
    backtrack(price, special, needs, 0, sum);
    cout << cost << endl;
    return 0;
}
******************************************************************************************************************
Problem P19. [算法课分支限界法]Partition to K Equal Sum Subsets
Given an integer array nums and an integer k, return true if it is possible to divide this array into k non-empty subsets whose sums are all equal.

#include<bits/stdc++.h>
using namespace std;
vector<int> nums;
int k;

bool dfs(int k,int cursum,int idx,int targetsum,vector<bool>& visited){
	if(k==0) return true;
	if(cursum > targetsum) return false;
	if(cursum == targetsum){
		return dfs(k-1,0,0,targetsum,visited);
	}
	for(int i=idx;i<nums.size();i++){
		if(visited[i]){
			continue;
		}
		cursum += nums[i];
		visited[i]=true;
		if(dfs(k,cursum,i+1,targetsum,visited)){
			return true;
		}
		visited[i]=false;
		cursum -= nums[i];
	}
	return false;
}
int main(){
	
	int x;
	while(cin>>x){
		nums.push_back(x);
	}
	k=x;
	nums.pop_back();
	int sum=0;
	int maxx = INT_MIN;
	for(int i:nums){
		sum+=i;	
		maxx = max(maxx,i);
	}
	int n = nums.size();
//	sort(nums.begin(),nums.end());
	int aver = sum / k;
	if(sum%k!=0 || maxx > aver){
		cout<<"false"<<endl;
		return 0;
	}
	
	vector<bool> visited(n,false);
	if(dfs(k,0,0,aver,visited)){
		cout<<"true";
		return 0;
	}
	cout<<"false";
	return 0;
} 
******************************************************************************************************************
Problem P20. [算法课分支限界法]分割等和子集
给定一个非空的正整数数组 nums(nums.length < 5) ,请判断能否将这些数字分成元素和相等的两部分。
#include<bits/stdc++.h>
using namespace std;
vector<int> nums;
int k=2;

bool dfs(int k,int cursum,int idx,int targetsum,vector<bool>& visited){
	if(k==0) return true;
	if(cursum > targetsum) return false;
	if(cursum == targetsum){
		return dfs(k-1,0,0,targetsum,visited);
	}
	for(int i=idx;i<nums.size();i++){
		if(visited[i]){
			continue;
		}
		cursum += nums[i];
		visited[i]=true;
		if(dfs(k,cursum,i+1,targetsum,visited)){
			return true;
		}
		visited[i]=false;
		cursum -= nums[i];
	}
	return false;
}
int main(){
	
	int x;
	while(cin>>x){
		nums.push_back(x);
	}
//	k=x;
//	nums.pop_back();
	int sum=0;
	int maxx = INT_MIN;
	for(int i:nums){
		sum+=i;	
		maxx = max(maxx,i);
	}
	int n = nums.size();
//	sort(nums.begin(),nums.end());
	int aver = sum / k;
	if(sum%k!=0 || maxx > aver){
		cout<<"false"<<endl;
		return 0;
	}
	
	vector<bool> visited(n,false);
	if(dfs(k,0,0,aver,visited)){
		cout<<"true";
		return 0;
	}
	cout<<"false";
	return 0;
} 

******************************************************************************************************************
Problem P21. [算法课分支限界法]硬币问题
给定不同面额的硬币和一个总金额(面额、硬币数、总金额均不超过 10)。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
#include<bits/stdc++.h>
using namespace std;
int target;
vector<int> nums;
int cnt=0;
int bfs(int surplus, int index) {
    if (index < 0 || surplus < 0)
        return 0;
    if (surplus == 0)
        return 1;
    int number = 0;
    for (int i = index; i >= 0; i--) {
        number += bfs(surplus - nums[i], i);
    }
    return number;
}

int main(){
	cin>>target;
	int x;
	while(cin>>x){
		nums.push_back(x);
	}
	sort(nums.begin(),nums.end());
	vector<int> dp(target,0);
	cout<<bfs(target,nums.size()-1)<<endl;

	return 0;
} 


******************************************************************************************************************
Problem P22. [算法课动态规划] 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
#include<bits/stdc++.h>
using namespace std;

vector<int> nums;

int rob(vector<int> &nums) {
    if (nums.empty()) {
        return 0;
    }
    int size = nums.size();
    if (size == 1) {
        return nums[0];
    }
    vector<int> dp = vector<int>(size, 0);
    dp[0] = nums[0];
    dp[1] = max(nums[0], nums[1]);
    for (int i = 2; i < size; i++) {
        dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
    }
    return dp[size - 1];
}

int main(){
	int x;
	while(cin>>x){
		nums.push_back(x);
	}
	cout<<rob(nums);
	return 0;
}
******************************************************************************************************************
Problem P23. [算法课动态规划] 戳气球
有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
#include<bits/stdc++.h>
using namespace std;
int res;
vector<int> vec;
vector<vector<int>> rec;
vector<int> val;

int solve(int left, int right) {
    if (left >= right - 1) {
        return 0;
    }
    if (rec[left][right] != -1) {
        return rec[left][right];
    }
    for (int i = left + 1; i < right; i++) {
        int sum = val[left] * val[i] * val[right];
        sum += solve(left, i) + solve(i, right);
        rec[left][right] = max(rec[left][right], sum);
    }
    return rec[left][right];
}

int maxCoins(vector<int> &nums) {
    int n = nums.size();
    val.resize(n + 2);
    for (int i = 1; i <= n; i++) {
        val[i] = nums[i - 1];
    }
    val[0] = val[n + 1] = 1;
    rec.resize(n + 2, vector<int>(n + 2, -1));
    return solve(0, n + 1);
}

int main(){
	int data;
    while (cin >> data)
        vec.push_back(data);
    res = maxCoins(vec);
    cout << res;
	return 0;
} 
******************************************************************************************************************
Problem P24. [算法课贪心] 分发糖果
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求,给这些孩子分发糖果:
#include<bits/stdc++.h>
using namespace std;
vector<int> vec;
int res;

int candy(vector<int> &ratings) {
    int n = ratings.size();
    vector<int> left(n);
    for (int i = 0; i < n; i++) {
        if (i > 0 && ratings[i] > ratings[i - 1]) {
            left[i] = left[i - 1] + 1;
        } else {
            left[i] = 1;
        }
    }
    int right = 0, ret = 0;
    for (int i = n - 1; i >= 0; i--) {
        if (i < n - 1 && ratings[i] > ratings[i + 1]) {
            right++;
        } else {
            right = 1;
        }
        ret += max(left[i], right);
    }
    return ret;
}


int main(){
	int data;
    while (cin >> data)
        vec.push_back(data);
    res = candy(vec);
    cout << res;
	return 0;
} 

******************************************************************************************************************
Problem P25. [算法课深度优先搜索] 水壶问题
有两个水壶,容量分别为 jug1Capacity 和 jug2Capacity 升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 targetCapacity 升。
#include<bits/stdc++.h>
using namespace std;
int res;
vector<int> vec;

bool canMeasureWater(int x, int y, int z) {
    using PII = pair<int, int>;
    stack<PII> stk;
    stk.emplace(0, 0);
    auto hash_function = [](const PII &o) { return hash<int>()(o.first) ^ hash<int>()(o.second); };
    unordered_set<PII, decltype(hash_function)> seen(0, hash_function);
    while (!stk.empty()) {
        if (seen.count(stk.top())) {
            stk.pop();
            continue;
        }
        seen.emplace(stk.top());

        auto [remain_x, remain_y] = stk.top();
        stk.pop();
        if (remain_x == z || remain_y == z || remain_x + remain_y == z) {
            return true;
        }
        // 把 X 壶灌满。
        stk.emplace(x, remain_y);
        // 把 Y 壶灌满。
        stk.emplace(remain_x, y);
        // 把 X 壶倒空。
        stk.emplace(0, remain_y);
        // 把 Y 壶倒空。
        stk.emplace(remain_x, 0);
        // 把 X 壶的水灌进 Y 壶,直至灌满或倒空。
        stk.emplace(remain_x - min(remain_x, y - remain_y), remain_y + min(remain_x, y - remain_y));
        // 把 Y 壶的水灌进 X 壶,直至灌满或倒空。
        stk.emplace(remain_x + min(remain_y, x - remain_x), remain_y - min(remain_y, x - remain_x));
    }
    return false;
}

int main(){
	int data;
    while (cin >> data)
        vec.push_back(data);
    res = canMeasureWater(vec[0], vec[1], vec[2]);
    if (res) {
        cout << "true";
    } else {
        cout << "false";
    }
	return 0;
} 
******************************************************************************************************************
Problem P26. [算法课动态规划] 摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
//摆动序列
//如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。
//第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
#include<bits/stdc++.h>
using namespace std;
int res;
vector<int> vec;

int wiggleMaxLength(vector<int> &nums) {
    int n = nums.size();
    if (n < 2) {
        return n;
    }
    vector<int> up(n), down(n);
    up[0] = down[0] = 1;
    for (int i = 1; i < n; i++) {
        if (nums[i] > nums[i - 1]) {
            up[i] = max(up[i - 1], down[i - 1] + 1);
            down[i] = down[i - 1];
        } else if (nums[i] < nums[i - 1]) {
            up[i] = up[i - 1];
            down[i] = max(up[i - 1] + 1, down[i - 1]);
        } else {
            up[i] = up[i - 1];
            down[i] = down[i - 1];
        }
    }
    return max(up[n - 1], down[n - 1]);
}


int main(){
	int data;
    while (cin >> data)
        vec.push_back(data);
    res = wiggleMaxLength(vec);
    cout << res;
	return 0;
} 
******************************************************************************************************************
Problem P27. [算法课滑动窗口] 最长不重复子串
给定一个字符串 ss ,请你找出其中不含有重复字符的最长子串的长度。
//最长不重复子串
//给定一个字符串 ss ,请你找出其中不含有重复字符的最长子串的长度。
#include<bits/stdc++.h>
using namespace std;

string str;
int res;

int lengthOfLongestSubstring(string s) {

    int s_size = s.size();
    int left = 0;
    int answer = 0;
    unordered_set<char> st;

    for (int right = 0; right < s_size; ++right) {
        while (st.find(s[right]) != st.end()) {
            st.erase(s[left]);
            ++left;
        }
        st.insert(s[right]);
        answer = max(answer, right - left + 1);
    }

    return answer;
}


int main(){
	getline(cin, str);
	res = 0;
    res = lengthOfLongestSubstring(str);
    cout << res;
	return 0;
} 
******************************************************************************************************************

;