/*单词拆分on^2
动态规划,先初始化dp为false。dp[i]表示s中前i位能否用wordDict中的单词表示
初始化dp[0]=true,代表空字符可以被表示
遍历字符中的所有子串,将满足要求的设为true
*/
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size()+1,false);
unordered_set<string> m(wordDict.begin(),wordDict.end());
dp[0] = true;
for(int i = 1;i <= s.size();++i){
for(int j = 0;j<i;++j){
if(dp[j] && m.find(s.substr(j,i-j)) != m.end()){
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}
};
/*多数元素nlogn
排序,因为出现次数>[n/2]且排序后相同元素相邻,
则多数元素一定可以在中间找到
*/
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(),nums.end());
return nums[nums.size()/2];
}
};
/*摆动序列sn
如果总数小于2,直接输出
n>2时,将数组中的后一个依次与前一个作比较,初始化a、b=1,分别代表上升与下降,
当出现数据摆动时,a、b才满足加一条件,最后输出其最大值
*/
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size(),a=1,b=1;
if(n < 2) return n;
for(int i = 1;i<n;i++){
if(nums[i]<nums[i-1]) a = b+1;
if(nums[i]>nums[i-1]) b = a+1;
}
return max(a,b);
}
};
/*sn
初始化dp,dp[i]:凑足总额为i所需钱币的最少个数;
dp[i]必须初始化为一个最大的数,否则就会在min比较的过程中被初始值覆盖,所以下标非0的元素都是应该是最大值
凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0
凑足总额为i-coins的最少个数为dp[i-coins],那么只需要加上一个钱币coins即dp[i-coins]+1就是dp[i]
*/
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,amount+1);
dp[0]=0;
for(int i =0;i < dp.size();i++){
for(int coin : coins){
if(i-coin<0) continue;
dp[i] = min(dp[i],1+dp[i-coin]);
}
}
return (dp[amount] == amount+1) ? -1 : dp[amount];
}
};
5.递增子序列n
class Solution {
public:
bool is_first(const vector<int> &num, int last, int pos) {
for(int i = last+1; i < pos; i++) {
if(num[i] == num[pos]) {
return false;
}
}
return true;
}
void dfs(const vector<int> &nums, int last, int pos, vector<int> &stack, vector<vector<int>> &anw) {
if(nums.size() == pos) { return; }
if((stack.empty() || nums[pos] >= stack.back()) && is_first(nums, last, pos)) {
stack.push_back(nums[pos]);
if(stack.size() >= 2) {
anw.push_back(stack);
}
dfs(nums, pos, pos+1, stack, anw);
stack.pop_back();
}
dfs(nums, last, pos+1, stack, anw);
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
vector<vector<int>> anw;
vector<int> stack;
dfs(nums, -1, 0, stack, anw);
return anw;
}
};
归并nlogn
/********** End **********/
temp[k++]=arr[j++];
}
//将临时空间的合并结果拷贝到原有的数组上
copy(temp.begin(),temp.end(),arr.begin()+start);
while(j<=end){
}
temp[k++]=arr[i++];
while(i<=mid){
//拷贝剩下的数。
}
}
temp[k++]=arr[j++];
else{
}
temp[k++] = arr[i++];
if(arr[i]<=arr[j]){
while(i<=mid && j<=end){
//?
//在两个有序数组中选择较小者存放至临时空间,把较小的先放到temp中再把剩下放到temp中。
/********** Begin *********/
int i=start,j =mid+1,k=0;
//申请临时空间存放合并的有序结果
vector<int> temp(end-start+1);
// 请在这里补充代码,完成本关任务
{
// 实现两个有序数组arr[start...mid]和arr[mid+1...end]合并
void merge(vector<int> &arr, int start, int mid, int end)
3.2快排nlogn
#include "sort_.h"
int partition(vector<int> &arr, int left, int right)
// 编程实现arr[left, right]分区:选定一个基准,左边比基准小,右边比基准大
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int pivotIndex;
int i,j;
pivotIndex = left;
//挑选左边的为基准值。
i=j=left+1;
while(j<=right){
if(arr[j]<arr[pivotIndex]){
swap(arr[i],arr[j]);
i++;
}
j++;
}
swap(arr[pivotIndex],arr[i-1]);
//进过一轮比较后换一个p。
return i-1;
3.k个元素
#include <iostream>
#include <vector>
using namespace std;
// 使用快速排序中的分区操作
int partition(vector<int> &array, int left, int right)
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int i,j;
int prov;
prov =left;
i = j = left+1;
while(j<=right){
if(array[j]<array[prov]){
swap(array[i],array[j]);
i++;
}
j++;
}
swap(array[prov],array[i-1]);
return i-1;
/********** End **********/
}
int·quickSelect(vector<int>·&array,·int·left,·int·right,·int·k)
{
int·partitionIndex;
partitionIndex=partition(array,left,right);
//请在这里补充代码,完成本关任务
/**********·Begin·*********/
if(k==partitionIndex-left+1){
return array[partitionIndex];
}
else if(k<partitionIndex-left+1){
return quickSelect(array,left,partitionIndex-left+1,k);
}
else if(k>partitionIndex-left+1){
return quickSelect(array,partitionIndex+1,right,k-(partitionIndex-left+1));
}
/**********·End·**********/
}
int main(){
vector<int>·a;
vector<int>::iterator·it;
int n, k,i;
cin >> n >> k;
a.resize(n);
for(it = a.begin(); it != a.end(); it++){
cin>>*it;
}
// 输出第k小元素
cout<<quickSelect(a, 0, a.size()-1, k)<<endl;
return 0;
}
4.最大连续子序列的和
#include <vector>
#include <iostream>
using namespace std;
// 求解最大连续子序列和的相关函数
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int maxCrossSum(vector<int> arry,int left,int mid,int right){
int sum,maxSumLeft,maxSumRight,i;
maxSumleft = array[mid];
sum=0;
for(i= mid;i<=left;i--){
sum+=array[i];
if(sum>maxSumleft){
maxSumleft =sum;
}
}
maxSumRight=array[mid+1];
sum=0;
for(i=mid+1;i<=right;i++){
sum+=array[i];
if(sum>maxSumRight){
maxSumRight=sum;
}
}
int maxSubarraySum(vector<int> array,int left,int right){
if(left==right)
return array[left];
int mid =(left+right)/2;
int s1 = maxSubarraySum(array,left,mid);
int s2 = maxSubarraySum(array,mid+1,right);
int s3 = maxCrossSum(array,left,mid,right);
return max(max(s1,s2),s3);
}
/********** End **********/
int·main(){
vector<int> a;
vector<int>::iterator it;
int n;
→ cin·>>·n;
→ a.resize(n);
→ for(it·=·a.begin();·it·!=·a.end();·it++){
→ → cin>>*it;
→ }
→
····//·输出
····//·请在这里补充代码,完成本关任务
····/**********·Begin·*********/
····cout<<maxSubarraySum(a,0,a.size()-1);
····
····/**********·End·**********/
→
→ return·0;
}
幂集问题
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> nSet; // 原始集合
vector<vector<int>> powerSet; // 存储各个子集的幂集结果
void dfs(int i, vector<int> &nodeSet)
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int n=nSet.size();
if(i==n)
powerSet.push_back(nodeSet);
else{
vector<int> newset;
newset=nodeSet;
newset.push_back(nSet[i]);
dfs(i+1,newset);
dfs(i+1,nodeSet);
}
/********** End **********/
}
全排列
vector<int> nSet; // 需要排列的多个元素的原始集合
vector<bool> used; // 第1,2,3,...,n个元素是否已用于排列
vector<int> x; // 排列解
vector<vector<int>> results;// 存储各个排列结果
void dfs(int idx)
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int i;
if(idx==n)
{
for(i=0;i<n;i++)
cout<<x[i];
cout<<endl;
}
else{
for(i=0;i<n;i++)
{
if(used[i]==false){
used[i]=true;
x[idx]=nSet[i];
dfs(idx+1);
used[i]=false;
}
}
}
/********** End **********/
}
7分支的01背包
1.#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int maxv = 0; //存放最大价值,初始为最小值
vector<int> bestx; //存放最优解,全局变量
int n, W; // n:物品数量,W:重量限制
vector<int> w; // 各个物品重量
vector<int> v; // 各个物品价值
struct NodeType //队列中的结点类型
{
int i; //当前结点在搜索空间中的层次
int w; //当前结点的总重量
int v; //当前结点的总价值
vector<int> x; //当前结点包含的解向量,若x为{1,0,0,1},表示子集中只有第1个和第4个物品
int ub; //upper bound,上界,不计重量限制的最大总价值
bool operator<(const NodeType &s) const //重载<关系函数
{
return ub<s.ub; //ub越大越优先出队
}
};
void bound(NodeType &e) //计算结点e的总价值上界
{
/* 请在这里填写答案 */
/********** Begin **********/
int i = e.i ;
int sumv = e.v ;
while ( i < n ){
sumv += v [ i ]; i ++;}
e.ub = sumv ;
/********** End **********/
}
void EnQueue(NodeType e,priority_queue<NodeType> &qu) //结点e是否进队qu以及相应处理
{
/* 请在这里填写答案 */
/********** Begin **********/
if ( e.i == n ){
if ( e.w <= W && e.v > maxv ){
maxv = e.v ;
bestx = e.x ;}}
else qu.push ( e );
/********** End **********/
}
void bfs() //求0/1背包的最优解
{
NodeType e,e1,e2; //定义3个结点
priority_queue<NodeType> qu; //定义一个队列
e.i=0; //根结点置初值,其层次计为0
e.w=0;
e.v=0;
bound(e);
EnQueue(e,qu); //根结点进队
while (!qu.empty()) //队不空循环
{
e=qu.top();
qu.pop(); //出队结点e
/* 请在这里填写答案 */
/********** Begin **********/
if ( e.ub > maxv ){
if ( e.w + w [ e.i ]<= W ){
e1.i= e.i +1;
e1.w= e.w + w [e.i];
e1.v= e.v + v [e.i];
e1.x= e.x ;
e1.x.push_back (1);
e1.ub= e.ub ;
EnQueue (e1,qu);}
e2.i= e.i +1;
e2.w=e.w;
e2.v= e.v;
e2.x=e.x ;
e2.x.push_back (0); bound (e2);
if (e2.ub>maxv)
EnQueue (e2,qu);}
/********** End **********/
}
}
int main()
{
int iw, iv, i;
cin >> n >> W;
for(i = 0; i < n; i++){
cin>>iw;
w.push_back(iw);
}
for(i = 0; i < n; i++){
cin>>iv;
v.push_back(iv);
}
bfs();
cout<<maxv<<endl;
return 0;
}
2.任务分配分支
#include <iostream>
#include <queue>
#include <vector>
#include <limits>
using namespace std;
#define MAXN 21
int n; // 元素个数
int c[MAXN][MAXN];
vector<int> bestx; // 最优解
int mincost = numeric_limits<int>::max(); // 最优解的成本
struct NodeType //队列中的结点类型
{
int i; //当前结点在搜索空间中的层次
vector<int> x; //当前结点包含的解向量(排列结果)
vector<bool> used; //当前各元素是否已用于排列的情况
int cost; //当前排列对应成本总和
int lb; //lower bound,下界,理想情况下最小总成本,不一定能实现
bool operator<(const NodeType &s) const //重载<关系函数
{
return lb>s.lb; // 默认最大堆,反序后下界lb最小的先出队
}
};
void bound(NodeType &e) //求结点e在理想(可能非现实)情况下的下界(最小总成本)
{
/* 请在这里填写答案 */
/********** Begin **********/
int minsum =0;
for (int i=e.i;i < n;i++){
int minc=numeric_limits< int>::max ();
for ( int j=0; j < n ; j++){
if (e.used [ j ]==false && c[ i ][ j ]<minc)
minc=c[ i ][ j ];}
minsum += minc;}
e.lb=e.cost+minsum;
/********** End **********/
}
void bfs() // 优先队列式搜索排列树,沿用队列式搜索中的函数名bfs
{
NodeType e,e1; //定义结点
priority_queue<NodeType> qu; //定义一个优先队列
e.i = 0; //根结点置初值,其层次计为0
e.used.resize(n, false); //根结点中没有任何元素已经用于排列
e.cost = 0;
bound(e);
qu.push(e); //根结点进队
while (!qu.empty()) //队不空循环
{
e = qu.top(); // priority_queue使用top(), queue使用front()
qu.pop(); //出队结点e
/* 请在这里填写答案 */
/********** Begin **********/
if (e.lb < mincost){
for(int k=0; k < n;k++){
if (e.used [ k ]== false){
e1.i = e.i +1;
e1.x = e.x ;
e1.x.push_back ( k );
e1.used= e.used ;
e1.used[ k ]= true ;
e1.cost = e.cost + c [ e.i ][ k ];
if (e1.i== n ){
if (e1.cost< mincost ){
mincost =e1.cost; bestx = e1.x;}}
else{
bound(e1);
if (e1.lb>=mincost)
continue;
qu.push(e1);}}}}
/********** End **********/
}
}
int main()
{
//输入
cin >> n;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
cin>>c[i][j];
bfs(); // 优先队列式搜索排列树
cout<< mincost <<endl;
return 0;
}
3.分支流水作业
#include <iostream>
#include <vector>
#include <limits>
using namespace std;
int n;
vector <int> a ;
vector <int> b ;
vector <int> nSet ;
vector <bool> used ;
int bestf = numeric_limits <int>::max();
int f1;
int f2;
vector <int> x ;
vector <int> bestx ;
int bound (){
int sum =0;
for ( int i =0; i < n ; i++) if ( used [ i ]== false )
sum += b [i] ;
return sum ;
}
void dfs ( int idx ){
int i ;
int tmpf2; if ( idx == n ){ if (f2< bestf ){
bestf =f2;
bestx = x ;}} else {
for ( i =0; i < n ; i ++){ if ( used [ i ]== false ){ used [ i ]= true ;
x [ idx ]= nSet [i];f1+=a[i];
tmpf2=f2;
f2= max (f1,f2)+ b [ i ]; if (f2+ bound ()< bestf ) dfs ( idx +1);
used [ i ]= false ;f1-= a [ i ];f2=tmpf2;}}}
}
int main (){
cin >> n ;
a . resize ( n );
b . resize ( n );
for ( int i =0; i < n ; i ++)
cin >> a [ i ]>> b [ i ];
nSet . resize ( n ); used . resize ( n ); x . resize ( n );
for ( int i =0; i < n ; i ++){
nSet [ i ]= i ; used [ i ]= false ;}
dfs (0);
cout << bestf << endl ;
return 0;
}
8
1.部分背包
//求解背包问题的算法
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
const double EPS = 1e-6; //比较精度
//问题表示
int n;
double W; //限重
struct NodeType
{
double w;
double v;
double p; //p=v/w
bool operator<(const NodeType &s) const
{
return p > s.p + EPS; //按p递减排序
}
};
vector<struct NodeType> a; //物品结点数组
//求解结果表示
double maxv; // 最大价值
vector<double> x; // 最优装入方案中各个物品的装入数值
void Knap() // 求解部分背包问题
{
/* 请在这里填写答案 */
/********** Begin **********/
maxv=0;
double weight=W;
int i=0;
for(int i=0;i<n;i++){
if(a[i].w+EPS<=weight){
x.push_back(1);
weight-=a[i].w;
maxv+=a[i].v;
}
else if(weight>0+EPS){
double p=weight/a[i].w;
x.push_back(p);
maxv+=p*a[i].v;
weight=0;
}
else{
x.push_back(0);
}
}
/********** End **********/
}
int main()
{
cin >> n >> W;
a.resize(n);
int i;
for (i = 0; i < n; i++)
cin >> a[i].w >> a[i].v;
for (i = 0; i < n; i++) //求v/w
a[i].p=a[i].v/a[i].w;
sort(a.begin(), a.end()); //排序
Knap();
cout<<maxv<<endl;
return 0;
}
2.最优秀装载
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//问题表示
int n, W; //集装箱数目, 载重限制
vector<int> weight; //各集装箱重量,不用下标0的元素
//求解结果表示
int maxn; //存放最优解的集装箱总数目
vector<int> x; //存放最优解的各个集装箱装入情况,0不装入,1装入
void solve() //贪心算法求解最优装载问题
{
/* 请在这里填写答案 */
/********** Begin **********/
sort(weight.begin(),weight.end());
maxn=0;
int rest= W;
for(int i=0;i<n;i++){
if(rest>=weight[i]){
x.push_back(1);
rest-=weight[i];
maxn++;
}
else{
x.push_back(0);
}
}
/********** End **********/
}
int main()
{
cin>>n>>W;
weight.resize(n);
for (int i = 0; i < n; i++)
cin>>weight[i];
solve();
cout<<maxn<<endl;
return 0;
}
3.活动安排
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Action
{
/* 请在这里填写答案 */
/********** Begin **********/
int b;
int e;
bool operator<(const Action &s) const{
return e<s.e;
}
/********** End **********/
};
int n;
vector<struct Action> A;
//求解结果表示
vector<bool> flag; //标记选择的活动
int Count = 0; //选取的兼容活动个数
void solve() //求解最大兼容活动子集
{
/* 请在这里填写答案 */
/********** Begin **********/
sort(A.begin(),A.end());
int preEnd=0;
for(int i=0;i<n;i++){
if(A[i].b>=preEnd){
flag.push_back(true);
preEnd=A[i].e;
Count++;
}
else{
flag.push_back(false);
}
}
/********** End **********/
}
int main()
{
cin>>n;
for(int i = 0; i < n; i++){
Action t;
cin>>t.b>>t.e;
A.push_back(t);
}
solve();
cout<<Count<<endl;
return 0;
}
9
1.动态01背包
#include<iostream>
#include<algorithm>
using namespace std;
int w[210]={0};
int v[210]={0};
int flag[210]={0};
int arr[210][10000]={0};
int main()
{
int n=0,c=0;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
for(int i=1;i<=n;i++)//物品i
{
for(int j=1;j<=c;j++)//重量j
{
if(j>=w[i])
{
arr[i][j]=max(arr[i-1][j],arr[i-1][j-w[i]]+v[i]);
}
else arr[i][j]=arr[i-1][j];
}
}
printf("%d ",arr[n][c]);
int h=n,g=c;
while(h>=1)
{
if(arr[h][g]==arr[h-1][g])flag[h]=0;
else
{
flag[h]=1;
g=g-w[h];
}
h--;
}
return 0;
}
2.最长公共子序列
// // 最长公共子序列
#include<bits/stdc++.h>
using namespace std;
const int Size = 1010; //尽量用全局变量
int DP[Size][Size];
int DIR[Size][Size];
int LCS_length(string a, string b)
{
int M = a.size();
int N = b.size();
for(int i=1; i<=M; i++)
{
for(int j=1; j<=N; j++)
{
if(a[i-1] == b[j-1])
{
DP[i][j] = DP[i-1][j-1] + 1;
DIR[i][j] = 1;
}
else if(DP[i-1][j] >= DP[i][j-1])
{
DP[i][j] = DP[i-1][j];
DIR[i][j] = 2;
}
else
{
DP[i][j] = DP[i][j-1];
DIR[i][j] = 3;
}
}
}
return DP[M][N];
}
void LCS(string a, int i, int j)
{
if(i==0 || j==0) return;
if(DIR[i][j] == 1)
{
LCS(a, i-1, j-1);
cout<<a[i-1]; //a[i-1]==b[j-1]
}
else if(DIR[i][j]==2) LCS(a, i-1, j);
else if(DIR[i][j]==3) LCS(a, i, j-1);
}
void LCS2(string a, string b, int i, int j) //算法改进,不使用DIR数组,仅仅依靠DP数组以及a,b两个序列
{
if(i==0 || j==0) return;
if(a[i-1]==b[j-1])
{
LCS2(a, b, i-1, j-1);
}
else if(DP[i-1][j] > DP[i][j-1]) LCS2(a, b, i-1, j);
else LCS2(a, b, i, j-1);
}
int main()
{
string a, b;
while(cin>>a>>b && a!="GG")
{
cout<<LCS_length(a, b)<<endl;
// LCS(a, a.size(), b.size());
LCS2(a, b, a.size(), b.size());
}
system("pause");
return 0;
}
3.最小编辑距离
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int func(string word1, string word2)
{
int n1 = word1.size();
int n2 = word2.size();
int **dp=new int*[n1+1];
for(int i=0;i<n1+1;i++)
dp[i]=new int[n2+1];
for(int j=1;j<n2+1;j++)
dp[0][j] = j;
for(int i=1;i<n1+1;i++)
dp[i][0] = i;
dp[0][0]=0;
for(int i=1;i<n1+1;i++)
{
for(int j=1;j<n2+1;j++)
{
if (word1[i-1] == word2[j-1])
dp[i][j] = dp[i-1][j-1];
else
// 插入dp[i][j-1] ,删除dp[i-1][j] ,替换dp[i-1][j-1]
dp[i][j] = min(min(dp[i][j-1], dp[i-1][j]), dp[i-1][j-1] ) + 1;
}
}
return dp[n1][n2];
}
int main()
{
string str1,str2;
cin>>str1>>str2;
int res=func(str1,str2);
cout<<res<<endl;
return 0;
}
综合题的重点题型准备考试的小练习
于 2023-06-01 09:11:12 首次发布