算法笔记


title: 算法笔记练习
date: 2021-03-12 21:56:11
tags:
categories:

  • C++

算法笔记一些习题

文章目录

第二章

2.7 指针

void swap(int* a,int* b){
	int temp;
	temp=*a;
	*a=*b;
	*b=temp;
}

不能int* temp; *temp= *a;因为指针变量存放是随机的

可以int x; int* temp=&x;赋初值

引用

函数的参数是作为局部变量的,对局部变量的操作不会影响外部变量。

不使用指针,使用C++的“引用”(别名)

只需要在函数参数类型后面加个&就可以了

和取地址运算符区分开,引用不是取地址的意思

2.8 结构体

sruct stu{
	int id;
	stu* next;
}s,*P;

(*p).id
(*p).next

p->id;
p->next;

初始化结构体:构造函数

sruct stu{
	int id;
	stu(int id){
		id=x;
	}
};

2.9 浮点数比较

修正

第三章

3.1.简单模拟

☆1032 挖掘机技术哪家强 (20 分)

为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

输入格式:

输入在第 1 行给出不超过 105 的正整数 N,即参赛人数。随后 N 行,每行给出一位参赛者的信息和成绩,包括其所代表的学校的编号(从 1 开始连续编号)、及其比赛成绩(百分制),中间以空格分隔。

输出格式

在一行中给出总得分最高的学校的编号、及其总分,中间以空格分隔。题目保证答案唯一,没有并列。

输入样例

6
3 65
2 80
1 100
2 70
3 40
3 0

输出样例

2 150
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,id,score,max=0,key=-1;
	int sum[100010];//={0} 
	memset(sum,0,sizeof(sum));
	cin>>n;
	for(int i=0;i<n;i++){//while不可取
		//cin>>id>>a[id];
		cin>>id>>score;
		sum[id]+=score;
	}
	for(int i=1;i<=n;i++){//从1开始写外面 
		if(sum[i]>max){
			max=sum[i];
			key=i;
		}
	}
	cout<<key<<' '<<max;
	return 0;	
}

3.2查找元素

3.3图形输出

☆1036 跟奥巴马一起编程 (15 分)

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014 年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入格式

输入在一行中给出正方形边长 N(3≤N≤20)和组成正方形边的某种字符 C,间隔一个空格。

输出格式

输出由给定字符 C 画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的 50%(四舍五入取整)。

输入样例

10 a

输出样例

aaaaaaaaaa
a        a
a        a
a        a
aaaaaaaaaa
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	char c;
	cin>>n>>c;
	for(int i=0;i<n;i++)
		printf("%c",c);
	printf("\n");
	int t;
	
	double x=(double)n/2;//(double)
	t=x>(int)x?(int)x+1:(int)x;
//	if(n%2==1)
//		t=n/2+1;
//	else
//		t=n/2;
	 for(int i=2;i<=t-1;i++){
	 	printf("%c",c);
	 	for(int j=0;j<n-2;j++)
	 		printf(" ");
	 	printf("%c\n",c);
	 }
	 for(int i=0;i<n;i++)
		printf("%c",c);
	return 0;	
} 

总结:四舍五入、转换类型

//int 舍弃小数点后
#include<iostream>
using namespace std;
int main()
{
	int n=11;
	double a=(double)n/2;//把(int)n转换为 (double)n,否则x还是int型
    cout<<(int)a<<endl;  //向下取整
    cout<<(a>(int)a?(int)a+1:(int)a)<<endl;   //向上取整
    cout<<(int)(a+0.5)<<endl;//四舍五入  	
    return 0;
}
1022 D进制的A+B (20 分)

输入两个非负 10 进制整数 AB (≤230−1),输出 A+BD (1<D≤10)进制数。

输入格式

输入在一行中依次给出 3 个整数 ABD

输出格式

输出 A+BD 进制数。

输入样例

123 456 8

输出样例

1103
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b,d;
	cin>>a>>b>>d;
	int sum=a+b;
	int k=0;
	int ans[31];
	if(sum==0)
		cout<<0;
	while(sum){
		ans[k++]=sum%d;
		sum/=d;
	} 
	for(int i=k-1;i>=0;i--){
		cout<<ans[i];
	}
	return 0;
}

3.4 日期处理

判断闰年

(year%4==0&&year%100!=0)||(year%400==0)

3.6字符串处理

☆1009 说反话 (20 分)

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:

测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。

输出格式:

每个测试用例的输出占一行,输出倒序后的句子。

输入样例:

Hello World Here I Come

输出样例:

Come I Here World Hello

读入带空格的整个句子

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int num=0;
	char words[100];
	while(scanf("%c",&words[num])!=EOF){
		num++;
	}
	for(int i=0;i<num-1;i++){
		cout<<words[i];
	}
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int num=0;
	char words[100][100];
	while(scanf("%s",&words[num])!=EOF){//%s 
		num++;//单词数 
	}
	for(int i=num-1;i>=0;i--){
		cout<<words[i];//<<' ';
		if(i>0)
			cout<<' ';
	}
	//cout<<3;
	return 0;
}

gets读入空格

char words[500];
	gets(words);
//fanshou
#include<bits/stdc++.h>
using namespace std;
int main()
{
	char words[500];
	gets(words);
	int t=-1;
	for(int i=0;i<strlen(words)-1;i++){
		if(words[i]==' '){
			 for(int j=i-1;j>t;j--)
			 	cout<<words[j];
			cout<<' ';
			t=i;
		}	
	}
		for(int j=strlen(words)-1;j>t;j--)
			 	cout<<words[j];
	return 0;
}

strlen可以获得字符串真实长度,数组

strlen(words)
//a+b
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b;
	string m,n;
	cin>>a>>m>>b>>n;
	int suma=0,sumb=0;
	for(int i=0;i<m.length();i++){
		int t=m[i]-'0';//-'0'
		suma=(suma+t)*a;
	}
	suma/=a;// 
	for(int i=0;i<n.length();i++){
		int t=n[i]-'0';
		sumb=(sumb+t)*b;	
	}
	sumb/=b;
	cout<<suma+sumb;
	return 0;
}

string下标对单个字符进行访问,使用数字运算注意转换,m.length()

for(int i=0;i<m.length();i++){
		int t=m[i]-'0';//-'0'
		suma=(suma+t)*a;
	}
	suma/=a;//

getchar()识别换行符

另一种+

#include<bits/stdc++.h>
using namespace std;
int main()
{
	char a[100];
	gets(a);
	char words[100][100];//存单词 
	int r=0,h=0;
	for(int i=0;i<strlen(a);i++){
		if(a[i]!=' '){
			words[r][h++]=a[i];
		}
		else{
			words[r][h]='\0';//末尾添加结束符'\0' 
			r++;
			h=0;
		}
	}
	for(int i=r;i>=0;i--){//最后一个单词无空格,所以不是r-1 
		printf("%s",words[i]);
		if(i>0) printf(" ");
	}
return 0;
}

第四章

4.1排序

sort

比较字典序:strcmp函数

return strcmp(a.name,b.name)<0即a.name字典序<b.name

struct Student{
	char name[10];
	char id[10];
	int score;
	int r;
}stu[100];

//分数高,字典序小
bool cmp(Student a,Student b){
	if(a.score!=b.score)
		return a.score>b.score;
	else
		return strcmp(a.name,b.name)<0;
}

排名的实现,基于上述排序 1,2,2,2,5

stu[0].r=1;
for(int i=1;i<n;i++){
    if(stu[i].score==stu[i-1].score)
        stu[i].r=stu[i-1].r;
    else
        stu[i].r=i+1;//错!!!stu[i-1].r+1;
}

1025 PAT Ranking (25 分)

Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhejiang University. Each test is supposed to run simultaneously in several places, and the ranklists will be merged immediately after the test. Now it is your job to write a program to correctly merge all the ranklists and generate the final rank.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive number N (≤100), the number of test locations. Then N ranklists follow, each starts with a line containing a positive integer K (≤300), the number of testees, and then K lines containing the registration number (a 13-digit number) and the total score of each testee. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first print in one line the total number of testees. Then print the final ranklist in the following format:

registration_number final_rank location_number local_rank

The locations are numbered from 1 to N. The output must be sorted in nondecreasing order of the final ranks. The testees with the same score must have the same rank, and the output must be sorted in nondecreasing order of their registration numbers.

Sample Input:

2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

Sample Output:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

4.2散列

散列查找1 电话聊天狂人

给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。

输入格式:

输入首先给出正整数N(≤105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。

输出格式:

在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。

输入样例:

4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832

输出样例:

13588625832 3
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n;
	map<string,int> mp;
	string number,num;
	int max=0;
	for(int i=0;i<2*n;i++){
		cin>>number;
		mp[number]++;
		if(mp[number]>max){
			max=mp[number];
			num=number;
		}
	}
	int count=0;//1;肯定会和自己相同 
	for(map<string,int>::vector it=mp.begin();it!=mp.end();it++){
		if(it->second==max){
			count++;
			if(it->first<num){
				num=it->first;
			}
		}
	}
	if(count==1)
		cout<<num<<' '<<max;
	else
		cout<<num<<' '<<max<<' '<<count;
return 0;
}

4.3递归

⭐斐波那契数列

1,1,2,3,5,8,13,21,···

int F(int n){
	if(n==0||n==1) return 1;//递归边界
	else return F(n-1)+F(n-2);//递归式
}
全排列
int n;
int num[10],hash[10]={false};
void P(int index){//从[1]开始
	if(index=n+1) {
        for(int i=1;i<=n;i++){
            cout<<num[i];            
        }
        cout<<endl;
		return;
       }
	for(int i=1;i<=n;i++){
        if(hash[i]==false){
            num[index]=i;
            hash[i]=true;
            P(index+1);
            hash[i]=flaes;//例:n=3;1,2,3;[3]解决后释放[2]1,_,_ —>1,3,_
        }
    }
}

int main(){
    n=3;
    P(1);
    return 0;
}
n皇后问题

枚举1~n所有排列,判断排列是不是在同一对角线

暴力,先列出全排列,再从所有排列里找出合法的

int n;
int pnum[10],hash[10]={false};
int count=0;
void P(int index){
    if(index==n+1){
        bool flag=true;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(abs(i-j)==abs(pnum[i]-pnum[j])){//判断
                    flag=false;
                }
            }
        }
        if(flag==true) count++;
        return;
    }
    for(int i=1;i<=n;i++){
        if(hash[i]==false){
            pnum[index]=i;
            hash[i]=true;
            P(index+1);
            hash[i]=false;
        }
    }
}
回溯n皇后

产生排列时只产生合法的排列,

现有列出已不合法不继续往下递归,直接返回上层

int n;
int pnum[10],hash[10]={false};
int count=0;
void P(int index){
    if(index==n+1){
         count++;
        return;
    }
    for(int i=1;i<=n;i++){
        if(hash[i]==false){
            bool flag=true;
            for(int pre=1;per<index;per++){//遍历之前的皇后
                if(abs(index-per)==abs(pnum[index]-pnum[per])){
                    flag=false;
                    break;
                }        
            }
            if(flag){
                pnum[index]=i;
                hash[i]=true;     
                P(index+1);
                hash[i]=false;
            }
        }
    }
}

4.4贪心

1020 月饼 (25 分)

月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。

注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有 3 种月饼,其库存量分别为 18、15、10 万吨,总售价分别为 75、72、45 亿元。如果市场的最大需求量只有 20 万吨,那么我们最大收益策略应该是卖出全部 15 万吨第 2 种月饼、以及 5 万吨第 3 种月饼,获得 72 + 45/2 = 94.5(亿元)。

输入格式:

每个输入包含一个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N 表示月饼的种类数、以及不超过 500(以万吨为单位)的正整数 D 表示市场最大需求量。随后一行给出 N 个正数表示每种月饼的库存量(以万吨为单位);最后一行给出 N 个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。

输出格式:

对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后 2 位。

输入样例:

3 20
18 15 10
75 72 45

输出样例:

94.50
#include<bits/stdc++.h>
using namespace std;
struct MT {
	float store;
	float totle;
	float price;
};
bool cmp(MT a,MT b){
	return a.price>b.price;
} 
int main()
{
	int n,d;
	cin>>n>>d;
	MT mt[1010];
	for(int i=0;i<n;i++){
		cin>>mt[i].store;
	}
	for(int i=0;i<n;i++){		
		cin>>mt[i].totle;
		float t=mt[i].totle;
		mt[i].price=t/mt[i].store;
	}
	sort(mt,mt+n,cmp);
	float sum=0;
	for(int i=0;i<n;i++){
		if(d>=mt[i].store){
			sum+=mt[i].totle;
			d-=mt[i].store;
		}
		else{
			sum+=mt[i].price*d;
			break;
		}
	}
	printf("%.2f",sum);
}

1023 组个最小数 (20 分)

给定数字 0-9 各若干个。你可以以任意顺序排列这些数字,但必须全部使用。目标是使得最后得到的数尽可能小(注意 0 不能做首位)。例如:给定两个 0,两个 1,三个 5,一个 8,我们得到的最小的数就是 10015558。

现给定数字,请编写程序输出能够组成的最小的数。

输入格式:

输入在一行中给出 10 个非负整数,顺序表示我们拥有数字 0、数字 1、……数字 9 的个数。整数间用一个空格分隔。10 个数字的总个数不超过 50,且至少拥有 1 个非 0 的数字。

输出格式:

在一行中输出能够组成的最小的数。

输入样例:

2 2 0 0 0 3 0 0 1 0

输出样例:

10015558
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[60],num,count=0;
	for(int i=0;i<10;i++){
		cin>>num;
		for(int j=0;j<num;j++){
			a[count++]=i;
		}
	}
	if(a[0]==0){
		for(int i=1;i<count;i++){
			if(a[i]!=0){
				a[0]=a[i];//swap(num[0],num[i]);
				a[i]=0;
				break;
			}
		}
	}
	for(int i=0;i<count;i++){
		cout<<a[i];
	}
		
return 0;
}

4.5二分

• 二分查找(未理解)

a[] int binarySearch(int a[],int right,int left,int x){}

a binarySearch(a,0,n-1,6)

a[]严格递增序列

int binarySearch(int a[],int left,int right,int x){
	int mid;
	while(left<=right){
		mid=(right+left)/2;
        if(x==a[mid]) return mid;
		if(x>a[mid]) left=mid-1;
        else right=mid+1;
	}
	return -1;
}

int main(){
    const int n=10;
    int a[n]={1,3,4,6,7,8,10,11,12,15};
    printf("%d",binarySearch(a,0,n-1,6));
}

严格递减序列x<a[mid]

mid=left+(right-left)/2避免溢出

若a中元素可能重复:

求序列中第一个>=x元素L的位置以及第一个>x的元素R位置,存在区间左闭右开[L,R)

a取到n

#include<bits/stdc++.h>
using namespace std;
int lower_bound(int a[],int left,int right,int x){
	while(left<right){
        int mid=(left+right)/2;
        //cout<<"low:left="<<left<<" right="<<right<<" mid="<<mid<<"  a[mid]="<<a[mid]<<"\n";
        if(x<=a[mid]) right=mid;
        else left=mid+1;
    }
    return left;
}

int upper_bound(int a[],int left,int right,int x){
    	while(left<right){
        int mid=(left+right)/2;
       //cout<<"up:left="<<left<<" right="<<right<<" mid="<<mid<<"  a[mid]="<<a[mid]<<"\n";
        if(x<a[mid]) right=mid;//
        else left=mid+1;
    }
    return left;
}
int main(){
    const int n=13;
    int a[n]={1,3,4,6,6,6,6,7,8,10,11,12,15};
    printf("%d %d",lower_bound(a,0,n,6),upper_bound(a,0,n,6));
}
固定模板
• 二分拓展

计算根号2的近似值

const double eps=le-5;
double f(int x){
    return x*x;
}
double calSqrt(){
    double left=1,right=2,mid;
    while(right-left>eps){ //       
        mid=(left+right)/2;
        if(f(mid)>2) right=mid;
        else left=mid;
    } 
    return mid;//
}

求方程f(x)的根

const double eps=le-5;
double f(double x){
    return ...;
}
double solve(double L,double R){
    double left=L,right=R,mid;
    while(right-left>eps){ //       
        mid=(left+right)/2;
        if(f(mid)>0) right=mid;
        else left=mid;
    } 
    return mid;//
}

如果f(x)递减,只把需把if(f(mid)>0)改为if(f(mid)<0)

装水问题

木棒切割问题

4.6 two pointers

while(i<j){
	if(a[i]+a[j]==M){
		i=i+1;
		j=j-1;
	}
	else if(a[i]+a[j]>M){
		j--;
	}
	else if(a[i]+a[j]<M){
		i++;
	}
}

序列合并问题

int merge(int a[],int b[],int c[],int n,int m){
	int index=0,i=0,j=0;
	while(i<n&&j<m){
		if(a[i]<=b[j]){
			c[index++]=a[i++];
			//c[index++]=a[i];
			//i++;
		}
		else{
			c[index++]=b[j];
			j++;
		}
	}
	while(i<n) c[index++]=a[i++];
	while(j<m) c[index++]=b[j++];
	return index;
}
• 归并序列

2-路归并排序

递归实现

void mergeSort(int a[],int left,int right){
	if(left<right){
		int mid=(left+right)/2;
		mergeSort(a,left,mid);
		mergeSort(a,mid+1,right);
		merge(a,left,mid,mid+1,right)
	}
}

void merge(int a[],int L1,int R1,int L2,int R2){
	int index=0,i=L1,j=L2;
	while(i<R1&&j<R2){
		if(a[i]<=b[j]){
			c[index++]=a[i++];
			//c[index++]=a[i];
			//i++;
		}
		else{
			c[index++]=b[j];
			j++;
		}
	}
	while(i<n) c[index++]=a[i++];
	while(j<m) c[index++]=b[j++];
	for(int i=0;i<index;i++){
		A[L1+i]=c[i];
	}
}

非递归实现

void mergeSort(int a[]){
	for(int step=2;step/2<=n;step*=2){
		for(int i=1;i<=n;i+=step){
			int mid=i+step/2-1;
			if(mid+1<=n){
				merge(a,i,mid,mid+1,min(i+step-1,n));
			}
		}
	}
}
void mergeSort(int a[]){
	for(int step=2;step/2<=n;step*=2){
		for(int i=1;i<=n;i+=step){
			sort(a+i,a+min(i+step,n+1));
		}
	}
}
• 快速排序
int Partition(int a[],int left,int right){
	int temp=a[left];
	while(left<right){
		while(left<right&&a[right]>temp)  right--;//?
		a[left]=a[right];
		while(left<right&&a[left]<=temp)  left++;
		a[right]=a[left];
	}
	a[left]=temp;
	return left;
}
void quickSort(int a[],int left,int right){
	if(left<right){
		int pos=Parition(a,left,right);
		quickSort(a,left,pos-1);
		quickSort(a,pos+1,right);
	}
}

随机数

#include<time.h>
int main(){
	srand((unsigned)time(NULL));
	printf("%d",rand());
}

rand()%(b-a+1)+a [a,b]

4.7 其他高效技巧与算法

打表

递推

1040 有几个PAT (25 分)

字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位(P),第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位(P),第 4 位(A),第 6 位(T)。

现给定字符串,问一共可以形成多少个 PAT

输入格式:

输入只有一行,包含一个字符串,长度不超过105,只包含 PAT 三种字母。

输出格式:

在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。

输入样例:

APPAPT

输出样例:

2

对于字符串中每个A,左边P的个数与右边T的个数乘积

#include<bits/stdc++.h>
using namespace std;
const int MAX=100010;
const int MOD=1000000007; 
//char str[MAX];
int leftNumP[MAX]={0};
int main()
{
	
	//gets(str);
	//PTA不支持gets,无空格直接用string 
//	int x=0;
//	while(scanf("%c",&str[x])!=EOF){
//		x++;
//	}
	string s;
	cin>>s;
	for(int i=0;i<s.length();i++){
		if(i>0){
			leftNumP[i]=leftNumP[i-1];
		}
		if(s[i]=='P'){
			leftNumP[i]++;
		}
	}
	int ans=0,rightNumT=0;
	for(int i=s.length()-1;i>=0;i--){
		if(s[i]=='T'){
			rightNumT++;
		}else if(s[i]=='A'){
			ans=(ans+rightNumT*leftNumP[i])%MOD;
		}
	}
	printf("%d\n",ans);
	return 0;
}

随机选择算法

第五章 入门篇(3)–数学问题

5.1简单数学

1019 数字黑洞 (20 分)

给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的 6174,这个神奇的数字也叫 Kaprekar 常数。

例如,我们从6767开始,将得到

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
... ...

现给定任意 4 位正整数,请编写程序演示到达黑洞的过程。

输入格式:

输入给出一个 (0,104) 区间内的正整数 N

输出格式:

如果 N 的 4 位数字全相等,则在一行内输出 N - N = 0000;否则将计算的每一步在一行内输出,直到 6174 作为差出现,输出格式见样例。注意每个数字按 4 位数格式输出。

输入样例 1:

6767

输出样例 1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174

输入样例 2:

2222

输出样例 2:

2222 - 2222 = 0000
#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b){
	return a>b;
}
void to_array(int n,int num[]){
	for(int i=0;i<4;i++){
		num[i]=n%10;
		n/=10;
	}
}
int to_number(int num[]){
	int sum=0;
	for(int i=0;i<4;i++){
		sum=sum*10+num[i];
	}
	return sum;
}
int main()
{
	int n,min,max;
	cin>>n;
	int num[5];
	while(1){
		to_array(n,num);
		sort(num,num+4);
		min=to_number(num);
		sort(num,num+4,cmp);
		max=to_number(num);
		n=max-min;
		printf("%04d - %04d = %04d\n",max,min,n);
		if(n==6174||n==0)
			break;	                                                                                     
	}
return 0;
}

5.2最大公约数与最小公倍数

最大公约数

__gcd(a,b);
int gcd(int a,int b){
	if(b==0) return a;
	else return gcd(b,a%b);
}

最大公倍数 a*b/__gcd(a,b)

避免a*b溢出

(a/__gcd(a,b))*b

5.3 分数的四则运算

表示

struct Fraction{
	int up,down;
};

化简

Fraction reduction(Fraction result){
	if(result.down<0){
		result.up=-result.up;
		result.down=-result.down;
	}
	if(result.up==0){
		result.down=1;
	}
	else{
		int d=__gcd((abs(resulr.up),abs(result.down));
		result.up/=d;
		result.down/=d;
	}
	return result;
}

四则运算

加法

Fraction add(Fraction a,Fraction b){
	Fraction result;
	result.up=a.up*b.down+b.up*a.down;
	result.down=a.down*b.down;
	return reduction(result);
}

减法

Fraction add(Fraction a,Fraction b){
	Fraction result;
	result.up=a.up*b.down-b.up*a.down;
	result.down=a.down*b.down;
	return reduction(result);
}

乘法

Fraction add(Fraction a,Fraction b){
	Fraction result;
	result.up=a.up*b.up;
	result.down=a.down*b.down;
	return reduction(result);
}

除法

Fraction add(Fraction a,Fraction b){
	Fraction result;
	result.up=a.up*b.down;
	result.down=a.down*b.up;
	return reduction(result);
}

输出

void showResult(Fraction r){
	r=reduction(r);
	if(r.down==1)
		printf("ll%d",r.up);
	else if(abs(r.up)>r.down)
		printf("%d %d/%d",r.up/r.down,r.up%r.down,r.down);
	else 
		printf("%d/%d",r.up,r.down);
}

5.4素数

  • 1不是素数
  • 素数表长至少比n大1
  • i<maxn

素数判断

bool isPrime(int n){
	if(n<=1) return false;
	//int sqr=(int)sqrt(1*0*n);
	//for(int i=2;i<=sqr;i++){
	for(int i=2;i*i<=n;i++){
		if(n%i==0) return false;
	}
	return true;
}

素数表获取

for(int i=1;i<maxn;i++){
	if(isPrime(i)==true){
		prime[pnum++]=i;
		//p[i]=true;
	}
}

超过10^5:

—>埃氏筛

bool pr[maxn]={0}//?false
for(int i=2;i<maxn;i++){
	if(pr[i]==flase){
		prime[prnum++]=i;
		for(int j=i+1;j<maxn;j+=i){
			p[j]=true;
		}
	}
}

5.5 质因子分解

先打印素数表

struct factor{
	int x,cnt;
}f[10];

对一个正整数n来说,如果它存在1和本身之外的因子,那么一定是在sqrt(n)的左右成对出现。而这里把这个结论用在“质因子”上面,会得到一个强化结论:对一个正整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n)。

if(n==1)
if(n%prime[i]==0){
	f[num].x=prime[i];
	f[num].cnt=0;
	while(n%prime[i]==0){
		f[num].cnt++;
		n/=prime[i];
	}
	num++;
}
if(n!=1){
	f[num].x=n;
	f[num++].cnt=1;
}

5.6 大整数运算

存储

struct bign{
	int d[1000];
	int len;
	bign(){//构造函数,每次定义结构体变量时,都会自动对该变量进行初始化
		memset(d,0,sizeof(d));
		len=0;
	}
}
bign change(char str[]){
	bign a;
	a.len=strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i]=str[a.len-i-1]-'0';//倒着赋值
	}
	return a;
}

比较

int compare(bign a,bign b){
	if(a.len>b.len) return 1;
	else if(a,len<b.len) return -1;
	else{
		for(int i=a.len-1;i>=0;i--){
			if(a.d[i]>b.d[i]) return 1;
			else if(a.d[i]<b.d[i]) return -1;
		}
		return 0;
	}
}

四则运算

高精度加法

bign add(bign a,bign b){
	bign c;
	int carry=0;
	for(int i=0;i<a.len||i<b.len;i++){//以较长的为界限
		int temp=a.d[i]+b.d[i]+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	}
	if(carry!=0){
		c.d[c.len++]=carry;
	}
	return c;
}

高精度减法

bign sub(bign a,bign b){
	bign c;
	for(int i=0;i<a.len||i<b.len;i++){//以较长的为界限
		if(a.d[i]<b.d[i]){
			a.d[i+1]--;
			a.d[i]+=10;
		}
		c.d[c.len++]=a.d[i]-b.d[i];
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){//去除高位0,至少保留一个最低位
		c.len--;
	}
	return c;
}

高精度与低精度乘法

bign multi(bign a,int b){
	bign c;
	int carry=0;
	for(int i=0;i<a.len;i++){//以较长的为界限
		int temp=a.d[i]*b+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	}
	while(carry!=0){
		c.d[c.len++]=carry%10;
		carry/=10;
	}
	return c;
}

高精度与低精度除法

bign divide(bign a,int b,int& r){//r?o
	bign c;
	c.len=a.len;
	for(int i=a.len-1;i>=0;i--){
		r=r*10+a.d[i];//余数
		if(r<b) c.d[i]=0;
		else{
			c.d[i]=r/b;
			r=r%b;
		}
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return cbign add(bign a,bign b){
	bign c;
	int carry=0;
	for(int i=0;i<a.len||i<b.len;i++){//以较长的为界限
		int temp=a.d[i]+b.d[i]+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	}
	if(carry!=0){e
		c.d[c.len++]=carry;
	}
	return c;
}
}

5.7 拓展欧几里得算法

5.8组合数

n!有多少个质因子p

n!=(n/p+n/p^2…)

int cal(int n,int p){
	int ans=0;
	while(n){//向下取整
		ans+=n/p;
		n/=p;
	}
}
int cla(int n,int p){
	if(n<p) return 0;
	return n/p+cal(n/p,p)
}

公式:
C n m = n ! m ! ( n − m ) ! C_n^m=\frac{n!}{m!(n-m)!} Cnm=m!(nm)!n!
递推公式:
C n m = C n − 1 m + C n − 1 m − 1 C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1} Cnm=Cn1m+Cn1m1

long long C(long long n,long long m){
	if(m==0||m==n) return 1;
	return C(n-1,m)+C(n-1,m-1);
}

重复计算

long long res[67][67]={0};
long long C(long long n,long long m){
	if(m==0||m==n) return 1;
	if(res[n][m]!=0) return res[n][m];
	return res[n][m]=C(n-1,m)+C(n-1,m-1);
}

打表:

⭐杨辉三角
const int n=60;
void calC(){
	for(int i=0;i<=n;i++){
		res[i][0]=res[i][i]=1;
	}
	for(int i=2;i<=n;i++){
		for(int j=0;j<=i/2;j++){
			res[i][j]=res[i-1][j]+res[i-1][j-1];
			res[i][i-j]=res[i][j];//C(i,i-j)=C(i,j);
		}
	}
}

边乘边除

long long C(long long n,long long m){
	long long ans=1;
	for(long long i=1;i<=m;i++){
		ans=ans*(n-m+i)/i;
	}
	return ans;
}

。。。

第六章 C++标准模板库(STL)介绍

6.7 stack 栈

#include<stack>
using namespace std;
stack<int> st;
for(int i=1;i<=5;i++){
	st.push(i);//
}
printf("%d",st.top());//获得栈顶元素
st.pop();//弹出栈
if(st.empty()==true)//栈是空
st.size();//元素个数

模拟递归?

第七章 提高篇(1)——数据结构专题(1)

7.1 栈的应用

中缀转后缀


7.2 队列的应用

7.3 链表处理

struct node{
	typename data;//数据域?
	node* next;//指针域
};

申请动态内存:

malloc函数

typename*p=(typename*)malloc(sizeof(typename));
int*p=(int*)malloc(sizeof(int));

new

int*p=new int;

释放空间:

free函数,对应malloc,成对出现

free(p);//p为指针变量

delete运算符,对应new,成对出现

delete(p);

创建链表

#include<stdio.h>
#include<stdlib.h>
struct node{
    int data;
    node* next;
};
node* creat(int array[]){
    node *p,*pre,*head;
    head=new node;
    for(int i=0;i<5;i++){
        p=new node;
        p->data=array[i];
        p->next=NUll;
        pre->next=p;
        pre=p;
    }
    retuen head;
}
int main(){
    int array[5]={5,3,6,1,2};
    node* L=creat(array);
    L=L->next;
    while(L!=NULL){
        printf("%d",L->data);
        L=L->next;
    }
}

查找元素

int search(node* head,int x){
	int count=0;
	node* p=head->next;
	while(p!=NULL){
		if(p->data==x)
			count++;
		p=p->next;
	}
	return count;
}

插入元素

void insert(node* head,int pose,int x){
	node* p=head->next;
	node* pre=head;//p的前驱结点
	while(p!=NULL){
		if(p->data==x){
			pre->next=p->next;
			delete(p);//释放p
			p=pre->next
		}
		else{
			pre=p;
			p=p->next;
		}
	}
}

删除元素

void del(node* head,int x){
	node* p=head;
    for(int i=0;i<pose-1;i++){
    	p=p->next;//到插入位置前一个结点
    }
    node* q=new node;
    q->data=x;
    q->next=p->next;//新结点的下一个结点指向原来位置的结点(p的下一个结点)
    p->next=q;//插入位置前一个结点指向q
}

静态链表

hash

struct node{
	typename data;
	int next;
}node[size];


第八章 提高篇(2)搜索专题

· 深度优先搜索(DFS)

迷宫

背包问题

剪枝:

·广度优先搜索(BFS)
void BFS(int s){
	queue<int> q;
	q.push(s);
	while(!q.empty()){//不为空
		取出队首元素top
		访问队首元素top
		将队首元素出队
		将top下一层结点未入队的全部入队,并设置为已入队
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V01YYJ6d-1618672271019)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20210329211427751.png)]

tips:设置两个增量数组,来表示四个方向

int X[]={0,0,1,-1};
int Y[]={1,-1,0,0};

使用for循环枚举四个方向

for(int i=0;i<4;i++){
	newX=nowX+X[i];
	newY=nowY+Y[i];
}

枚举每一个位置的元素,如果为0,跳过;如果为1,ans+1,BFS查询相邻四个位置,(不出界),相邻位置为1,继续查询该位置相邻,直到整个1块被查询完,所有相邻1入队。

#include<cstdio>
#include<queue>
using namespace std;
const int maxn=100;
struct node{
    int x,y;
}Node;

int n,m;
int matrix[maxn][maxn];
bool inq[maxn][maxn]={false};
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};

bool judge(int x,int y){
    if(x>=n||y<=m||x<0||y<0) return false;
    if(matrix[x][y]==0||inq[x][y]=true) return false;
    retuen true;
}
void BFS(int x,int y){
    queue<node> q;//
    Node.x=x;
    Node.y=y;
    q.push(Node);//入队
    inq[x][y]=true;
    while(!q.empty()){
        node top=q.front();//取出队首元素
        q.pop();//队首元素出队
        for(int i=0;i<4;i++){
            int newX=nowX+X[i];
            int newY=nowY+Y[i];
            if(judge(newX,newY)){
                Node.x=newX;
                Node.y=newY;
                q.push(Node);
                inq[newX][newY]=true;
            }
        }
    }    
}
int main(){
    cin>>n>>m;
    int ans=0;
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++){
            cin>>matrix[x][y];
        }
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++){
            if(matrix[i][j]==1&&inq[j][j]==false){
                ans++;
                BFS(i,j);
            }
        }
    cout<<ans;
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jX0HKFwy-1618672271021)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20210330154047853.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FynwAiZ6-1618672271023)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20210330154201387.png)]

#include<cstdio>
#include<queue>
using namespace std;
const int maxn=100;
struct node{
    int x,y;
    int step;
}S,T,Node;//S起点,T终点

int n,m;
char matrix[maxn][maxn];
bool inq[maxn][maxn]={false};
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};

bool judge(int x,int y){
    if(x>=n||y<=m||x<0||y<0) return false;
    if(matrix[x][y]=='*') return false;
    if(inq[x][y]=true) return false;
    retuen true;
}
int BFS(){
    queue<node> q;//
    q.push(S);//起点入队
    inq[S.x][S.y]=true;
    while(!q.empty()){
        node top=q.front();//取出队首元素
        q.pop();//队首元素出队
        if(top.x=T.x&&top.y==T.y) return top.step;
        for(int i=0;i<4;i++){
            int newX=nowX+X[i];
            int newY=nowY+Y[i];
            if(judge(newX,newY)){
                Node.x=newX;
                Node.y=newY;
                Node.step=top.step+1;//
                q.push(Node);
                inq[newX][newY]=true;
            }
        }
    }   
    return -1;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<m;i++){
        getchar();//过滤每行后的换行符?
        for(int j=0;j<n;j++){         
            matrix[x][y]=getchar();//
        }
        maze[i][m+1]='\0';
    }      
    scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);
    S.step=0;
    
   
      
    cout<< BFS();
    return 0;
}

第九章 提高篇(3)–树

9.1 树与二叉树

二叉链表定义

struct node{
	typename data;
	node* lchild;
	node* rchild;
};

建树前根结点不存在

node* root=NULL;

新建结点

node* newNode(int v){
	node* Node=new node;
	Node->data=v;
	Node->lchild=NULL;
	Node->rchild=NULL;
	return Node;//返回新建结点地址
}

查找、修改

void search(node* root,int x,int newdata){
	if(root==NULL) return;
	if(root->data==x) root->data=newdata;
	search(root->lchild,x,newdata);
	search(root->rchild,x,newdata);
}

插入

*引用即在函数中修改root会直接修改原变量
void insert(node* &root,int x){//?根结点要使用引用
	if(root==NULL) {
		root=newNode(x);
		return;
	}
	if(){
		insert(root->lchild,x);
	}else{
		insert(root->rchild,x);
	}
}

二叉树创建

node* Greate(int data[],int n){
	node* root=NULL;
	for(int i=0;i<n;i++){
		insert(root,data[i]);
	}
	return root;
}

完全二叉树

任何一个结点x,左孩子2x,右孩子2x+1

数组存

  • 数组中元素存放顺序恰好为层序遍历序列
  • 判断叶节点,该结点x左子结点编号2x>结点总个数
  • 空结点:x>结点总个数

9.2 二叉树遍历

先序遍历

vvvoid preorder(node* root){
	if(root==NULL) return;
	printf("%d\n",root->data);
	preorder(root->lchild);
	preorder(root->rchild);
}

中序遍历

void inorder(node* root){
	if(root==NULL) return;
	inorder(root->lchild);
	printf("%d\n",root->data);
	inorder(root->rchild);
}

后序遍历

void postorder(node* root){
	if(root==NULL) return;
	postorder(root->lchild);
	postorder(root->rchild);
	printf("%d\n",root->data);
}

层序遍历

void layerorder(node* root){
	queue<node*> q;//存地址
	root->layer=1;
	q.push(root);
	while(!q.empty()){
		node* now=q.front();
		q.pop();
		printf("%d",now->data);
		if(now->lchild!=NULL) {
			now->lchild->layer=now->layer+1;
			q.push(now->lchild);
		}
		if(now->rchild!=NULL) {
			now->rchild->layer=now->layer+1;
			q.push(now->rchild);
		}
	}
}

给定一棵二叉树先序和中序,重建这棵二叉树

node* create(int preL,int preR,int inL,int inR){
	if(preL>preR) return NULL;
    node* root=new node;
    root->data=pre[preL];
    for(int k=inL;k<=inR;k++){
    	if(in[k]==pre[preL]) break;
    }
    int numLeft=k-inL;//左子树结点个数
    root->lchild=create(preL+1,prel+numLeft,inL,k-1)
    root->rchild=create(preL+numLeft+1,preR,k+1,inR);
    return root;
}
(未)A1020
二叉树静态实现

定义

struct node{
	typename data;
	int lchild;
	int rchild;
}Node[maxn];

结点生成

int index=0;
int newNode(int v){
	Node[index].data=v;
	Node[index].lchild=-1;
	Node[index].rchild=-1;
	return index++;
}

查找、修改

void search(int root,int x,int newdata){
	if(root=-1) return;
	if(Node[root].data==x){
		Node[root].data=newdata;
	}
	search(Node[root].lchild,x,newdata);
	search(Node[root].rchild,x,newdata);
}

插入,加引用

void insert(int &root,int x){
	if(root==-1) return;
	if() insert(Node[root].lchild,x);
	else insert(Node[root].rchild,x);
}

建立

int Creat(int data[],int n){
	int root=-1;
	for(int i=0;i<n;i++){
		insert(root,data[i]);
	}
	return root;
}

先、中、后、层序遍历

void preorder(int root){
	if(root==-1) return;
	printf("%d",root);
	preorder(Node[root].lchild);
	preorder(Node[root].rchild);
}

9.3 树的遍历

静态写法

struct node{
	typename data;
	int child[maxn];//vector child;?
}Node[maxn];

只需要树的结构,图的邻接表在树中的应用:vector child[maxn];

(未)A1053

9.4 二叉查找树(BST)

查找

void search(node* root,int x){
	if(root==NULL) return;
	if(x==root->data){
		printf("%d",root->data);
	}
	else if(x>root->data){
		search(root->rchild,x);
	}
	else search(root->lchild,x);
}

插入

void insert(node* root,int x){
	if(root==NULL) {
		root=newNode(x);
		return;
	}
	if(x==root->data){
		return;
	}
	else if(x>root->data){
		insert(root->rchild,x);
	}
	else insert(root->lchild,x);
}

9.6 并查集

int father[N]

father[1]=2,1的父亲结点是2

查找

递推

int findFather(int x){
	while(x!=father[x]){//不是根结点
		x=father[x];
	}
}

路径压缩:只找根结点

好朋友


第10章 提高篇(4)–图算法专题

10.2 图的存储

邻接矩阵

第11章 提高篇(5)–动态规划专题

记录重叠子问题的解

数塔问题

状态转移方程

递推写法,自底向上

递推写法从边界出发

#include<bits/stdc++.h>
int f[maxn][maxn],dp[maxn][maxn];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&f[i][j]);
    //边界
    for(int j=1;j<=n;j++){//最下
        dp[n][j]=f[n][j];
    }    
    for(int i=n-1;i>=1;i--)
        for(int j=1;j<=i;j++){
    //状态转移方程
            dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j];
		}
    cout<<dp[1][1];        
}

11.2 最大连续子序列和

dp[i]表示以a[i]结尾的连续序列最大

dp[0]=a[0];//边界
for(int i=0;i<n;i++){
    dp[i]=max(a[i],dp[i-1]+a[i]);
}
int k=0;
for(int i=0;i<n;i++){
    if(dp[i]>dp[k])
        k=i;
}
cout<<dp[k];

11.3 最长不下降子序列

dp[i]表示以a[i]结尾的最长不下降子序列长度

int ans=-1;
for(int i=0;i<n;i++){
    dp[i]=1;
    for(int j=0;j<i;j++){		
        if(a[i]>=a[j]&&dp[j]+1>dp[i]){//dp[j]+1>dp[i]:循环找到dp[i]最大
            dp[i]=dp[j]+1;
        }
    }
    ans=max(ans,dp[i]);
}
cout<<ans;

11.4 最长公共子序列

dp[i] [j]表示字符串A的 i 号位与字符串B的 j 号位之前 最长公共子序列的长度

int n;
gets(A+1);//从下标为1开始读入
int lenA=strlen(A+1);
B...
//边界
for(int i=0;i<=lenA;i++){
    dp[i][0]=0;
}
for(int j=0;j<=lenA;j++){
    dp[0][j]=0;
}
for(int i=1;i<=lenA;i++){
	for(int j=1;j<=lenB;j++){
        if(A[i]=B[j]){
            dp[i][j]=dp[i-1][j-1]+1;
        }else{
            dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
}
cout<<dp[lenA][lenB];

11.5 最长回文字串

递推写法从边界出发

dp[i] [j]表示s[i]到s[j]是否是回文字符串

第一遍将长度为3的字串,第二遍长度为4的。。。

int ans=1;
gets(s);
memset(dp,0,sizeof(dp));
//边界
for(int i=0;i<strlen(s);i++){
    dp[i][i]=0;
    if(i<len-1)
        if(s[i]==s[i+1]){
            dp[i][i+1]=1;
            ans=2;
        }
}
for(int l=3;l<=len;l++){
    for(int i=0;i+l-1<len;i++){//左
        int j=i+l-1;//右端点
        if(s[i]==s[j]&&dp[i+1][j-1]==1){
            dp[i][j]=1;
            ans=L;
        }
    }
}
cout<<ans;

11.6 DAG(有向无环图)最长路

不是很懂

不固定起点终点

dp[i]表示从i顶点出发能获得的最长路径长度

dp[i]=max{dp[j]+length[i->j]}

int DP(int i){
    if(dp[i]>0) return dp[i];
    for(int j=0;j<n;j++){
        if(G[i][j]!=INF)//如果有有向边
            dp[i]=max(dp[i],DP(j)+G[i][j]);
    }
    return dp[i];
}

求路径

int DP(int i){
    if(dp[i]>0) return dp[i];
    for(int j=0;j<n;j++){
        if(G[i][j]!=INF){//如果有有向边
            int temp=DP(j)+G[i][j];
            if(temp>dp[i]){
                dp[i]=temp;
                choice[i]=j;
            }        
        }
    }
    return dp[i];
}

void printPath(int i){
    printf("%d",i);
    while(choice[i]!=-1){
        i=choice[i];
        printf("->%d",i);
    }
}

固定终点

int DP(int i){
    if(vis[i]) return dp[i];
    vis[i]=true;//访问过了
    for(int j=0;j<n;j++){
        if(G[i][j]!=INF)//如果有有向边
            dp[i]=max(dp[i],DP(j)+G[i][j]);
    }
    return dp[i];
}

11.7 背包问题

01背包问题

dp[i] [v]表示前 i 件物品恰好装入容量为 v 的背包中 的最大价值

for(int i=1;i<=n;i++){
	for(int v=w[i];v<=V;v++){
		dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]);
	}
}

完全背包问题

for(int i=1;i<=n;i++){
	for(int v=w[i];v<=V;v++){
		dp[i][v]=max(dp[i-1][v],dp[i][v-w[i]]+c[i]);//
	}
}

滚动数组?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值