前言:
✌ 作者简介:CC++Edge淇,大家可以叫我--斯淇。(CSDN优质博客的建议加这一条)
个人主页:CC++Edge淇主页
如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步
如果感觉博主的文章还不错的话,还请不吝关注、点赞、收藏三连支持一下博主哦
人生格言:那个人应该是我!。
欢迎持续关注 | |
基本思路:1.把原问题分解为多个子问题!
2.确定状态:在动态规划中,往往将和子问题相关的各个变量的一组取值,称为一个“状态”。一个“状态 ”下的“值”,就是这个状态所对应子问题的解!(即数字所在的行列也就称为状态!)整个问题的时间复杂是状态数目乘以计算每个状态所需要时间!
3.确定一些初始状态(边界状态)的值!!
还有一点需要注意的是!(不是所有的问题都去尝试动态规划解决),他又使用的特点!1.问题具有最优结构性质2.无后效性!
动归的常用两种形式:
1)递归型:
优点:直观,同意编写
缺点:会爆栈,函数调用带来额外时间的开销!(个人觉得比递归慢一点)
2)递推型:效率高,有可能使用滚动数组节省时间
01背包问题
题目描述
一个旅行者有一个最多能装m公斤的背包,现在有n中物品,每件的重量分别是W1、W2、……、Wn,每件物品的价值分别为C1、C2、……、Cn, 需要将物品放入背包中,要怎么样放才能保证背包中物品的总价值最大?
提一提思路(动态规划):
#include
int main(){
int sum,i,j,l,p;
sum(i,0)=sum(0,j)=0 //这个是原本!
sum(i,j)=sum(j-1,j);//当这个数小于总数时即为下降
sum(i,j)=max{sum(v-1,j),sum(i-1,j)+sum(i,j+1)+sum(i,0)}
}
这个时候就得看这个sum(i,j)该如何控制第一种原因:要么就没有分进去,第二种原因:这些物品被装进去了
参考一下优秀CSDN博主的代码!!!
#include
#include
int V[100][100];//前i个物品装入容量为j的背包中获得的最大价值
int max(int a,int b){
if(a>=b)
return a;
else return b;
}
int KnapSack(int n,int weight[],int value[],int C){
//填表,其中第一行和第一列全为0,即 V(i,0)=V(0,j)=0;
for(int i=0;i
V[i][0]=0;
for(int j=0;j
V[0][j]=0;
//用到的矩阵部分V[n][C] ,下面输出中并不输出 第1行和第1列
printf("编号 重量 价值 "); //菜单栏 1
for(int i=1;i
printf(" %2d ",i);
printf("\n\n");
for(int i=1;i
printf("%2d %2d %2d ",i,weight[i-1],value[i-1]); //菜单栏 2 (weight与value都是从0开始存的,所以开始i=1时对应0的位置)
for(int j=1;j
if(j//包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的
V[i][j]=V[i-1][j];
printf("%2d ",V[i][j]);
}
else{ //还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个
V[i][j]=max(V[i-1][j],V[i-1][j-weight[i-1]]+value[i-1]);
printf("%2d ",V[i][j]);
}
}
printf("\n");
}
return V[n][C];
}
void Judge(int C,int n,int weight[]){ //判断哪些物品被选中
int j=C;
int *state=(int *)malloc(n*sizeof(int));
for(int i=n;i>=1;i--){
if(V[i][j]>V[i-1][j]){ //如果装了就标记,然后减去相应容量
state[i]=1;
j=j-weight[i-1];
}
else
state[i]=0;
}
printf("选中的物品是:");
for(int i=1;i
if(state[i]==1)
printf("%d ",i);
printf("\n");
}
int main(){
int n; //物品数量
int Capacity;//背包最大容量
printf("请输入背包的最大容量:");
scanf("%d",&Capacity);
printf("输入物品数:");
scanf("%d",&n);
int *weight=(int *)malloc(n*sizeof(int));//物品的重量
int *value=(int *)malloc(n*sizeof(int)); //物品的价值
printf("请分别输入物品的重量:");
for(int i=0;i
scanf("%d",&weight[i]);
printf("请分别输入物品的价值:");
for(int i=0;i
scanf("%d",&value[i]);
int s=KnapSack(n,weight,value,Capacity); //获得的最大价值
Judge(Capacity,n,weight); //判断那些物品被选择
printf("最大物品价值为: ");
printf("%d\n",s);
return 0;
}
基本概念
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
说一说思想:这个称为回溯法就相当于走一条路(比如一到二到三为一条路)走不通就直接往回走再重新走一次!尝试每一种可能
基本打法!!(先记住模板!)
#include
int app(int i,int x) //这里放进去参数!
{
if(i>x)
return 1;
else
return 2;
}
void dfs(int step,int k,int q){
if(step==1){
k=1;
}
//输出每一种可能!
{
q++;
//每次进行一次标记!!
return 0;
}
}
return 0;
}
找个列题玩玩!!
1.油田问题
问题:GeoSurvComp地质调查公司负责探测地下石油储藏。 GeoSurvComp现在在一块矩形区域探测石油,并把这个大区域分成了很多小块。他们通过专业设备,来分析每个小块中是否蕴藏石油。如果这些蕴藏石油的小方格相邻,那么他们被认为是同一油藏的一部分。在这块矩形区域,可能有很多油藏。你的任务是确定有多少不同的油藏。
input: 输入可能有多个矩形区域(即可能有多组测试)。每个矩形区域的起始行包含m和n,表示行和列的数量,
1
output: 对于每一个矩形区域,输出油藏的数量。两个小方格是相邻的,当且仅当他们水平或者垂直或者对角线相邻(即8个方向)。
#include
char p[100][100];//要么是*代表没有油要么是@表示有油
int i,k,sum,num,o,m,n;
int a[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{-1,1}};
int check(int x,int y){
if(x>=0&&x=0&&y'@')
return 1;
else
return 0;
}
int dfs(int x,int y){
int i,sum,num,app;
if(check(x,y)){
p[x][y]='#';
for(i=0;i
sum=x+a[i][0];
num=y+a[i][1];
dfs(sum,num);
}
return 1;
}
return 0;
}
int main(){
int i,j,k;
while(scanf("%d %d",&m,&n)==2){
if(m==0&&n==0)
break;
o=0;
for(i=0;i
scanf("%d",a[i]);
for(i=0;i
for(j=0;j
if(dfs(i,j)){
o++;
}
}
}
printf("%d\n",o);
}
}
return 0;
}
这里说一说广搜与深搜的比较
1.广搜一般用于状态表示比较简单、求最优策略的问题!
优点:他更像是一种完备策略(类似与万能解法)只有有问题就一定会有解答,而且,广度优先搜索找到的解,它还是最优的解法!!
但是它有一个缺点:就是太乱了(盲目性太强),尤其是当它与目标相比较靠近的时候,做了太多无用的搜索,占用的时间和空间会比较多(有些题目限制时间需要有慎重考虑)
2.深度搜索可以说基本上适用于大多数问题!
(只需要保持从起始状态下开始到末端状态下结束!)
贪心算法的定义:
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的一般步骤是(基本思路):
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解;
例题!!
设有M台完全相同的机器运行N个独立的任务,运行任务i所需要的时间为ti,要求确定一个调度方案,使得完成所有任务所需要的时间最短。假设任务已经按照其运行的时间从大到小来排序,算法基于最长运行时间作业优先的策略:按顺序先把每个任务分配到一台机器上,然后将剩余的任务一次放入最先空闲的机器。
#include
void app(int x,int y,int *m){
int num,k,l,q,i,j;
int a[50][50],p[100],sum[100];
for(i=0;i
p[i]=0;
for(j=0;j
a[i][j]=1;
}
}
for(i=0;i
a[i][0]=i;
p[i]+=m[i];
sum[i]=1;
}
for(i=x;i
num=p[0];
k=0;
for(j=0;j
if(num>p[j]){
num=p[j];
k=j;
}
}
a[i][sum[k]]=i;
sum[k]+=1;
p[k]=p[k]+m[i];
}
for(i=0;i
if(num
num=p[i];
}
}
printf("完成所有任务需要的时间:%d\n",num);
for(i=0;i
printf("%d",i);
}
for(j=0;j
if(a[i][j]==1){
break;
}
printf("%d\t",m[a[i][j]]);
}
printf("\n");
}
void main(){
int time[7]={16,14,6,5,4,3,2} ;
app(3,7,time);
}