动态规划学习总结:golang

动态规划
https://blog.csdn.net/qq_41785863/article/details/81457126

动态规划0:1背包:

import (
    "fmt"
)
func main() {
	var n,v int
	//n for number
	//v for package

	fmt.Scanf("%d %d",&n,&v)
	w:=make([]int,n)
	c:=make([]int,n)
	dp:=make([]int,v+1)
	for i :=0;i<n;i++{
		fmt.Scanf("%d",&w[i])
		fmt.Scanf("%d",&c[i])
	}
	for i:=0;i<n;i++{
		for j:=v;j>=w[i];j--{
			dp[j] = max(dp[j],dp[j-w[i]]+c[i])
		}
	}
	fmt.Println(dp[v])
}

func max(a,b int)int{
	if a>b{
		return a
	}
	return b
}

算法逻辑:
1)容积逆推,先放入一个物品,保证容积够,获取一个物品,容积够的情况下所有的价值
2)再放入第二个物品,当容积够的时候,将其放入,但是容积会相应减少第二个物品的重量,当剩余容积小于第一个物品的时候,将第一个物品拿出,所以是,dp[j-w[i]]+c[i],选择第一个物品在的时候dp[j]那个更大
3)依此类推到最后一个物品,算法结束

01背包算法2

package main

import (
	"fmt"
)

func main() {
	var n,v int
	//n for number
	//v for package

	fmt.Scanf("%d %d",&n,&v)
	w:=make([]int,n)
	c:=make([]int,n)
	dp:=make([][]int,n+1)
	for i:=0;i<=n;i++{
		dp[i] = make([]int,v+1)
	}
	for i :=0;i<n;i++{
		fmt.Scanf("%d",&w[i])
		fmt.Scanf("%d",&c[i])
	}
	for i:=1;i<=n;i++{
		for j:=1;j<=v;j++{
			if j<w[i-1] {
				dp[i][j] = dp[i-1][j]
			}else{
				dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i-1]]+c[i-1])
			}
		}
	}
	fmt.Println(dp[n][v])
}

func max(a,b int)int{
	if a>b{
		return a
	}
	return b
}

1)dp[i][j],i代表第i个物品,j容积,dp[i][j]也就是在容积为j,i个物品的情况下最大价值
2)从第i物品开始,遍历容积查看针对每个容积的价值,当容积不够第i个物品的时候,不放入,则价值是dp[i-1][j]
3)当容积够的时候,两种情况,要么放入要么不放入,不放入,则值为dp[i-1][j],放入,则值为上一个物品的容积-当前物品容积+当前物品价值,dp[i-1][j-w[i-1]]+c[i-1]

最长公共子序列

package main

import "fmt"

func main() {
	s1:="HelloWorld"
	s2:="loopr"
	dp:=make([][]int,len(s1)+1)
	for i:=0;i<=len(s1);i++{
		dp[i] = make([]int,len(s2)+1)
	}
	for i:=1;i<=len(s1);i++{
		for j:=1;j<=len(s2);j++{
			if s1[i-1]==s2[j-1]{
				dp[i][j] = dp[i-1][j-1] +1
			}else{
				dp[i][j] = max(dp[i][j-1],dp[i-1][j])
			}
		}
	}
	fmt.Println(dp[len(s1)][len(s2)])
}

//loor 四个
func max(a,b int)int{
	if a>b{
		return a
	}
	return b
}

1)dp[i][j],代表第一个字符串长度i的时候与第二个字符串长度j的时候最长的公共子字符串
2)当s1[i]==s2[j],则dp[i][j] = dp[i-1][j-1]+1
3)当不相等的时候因为要最长,所以选择i长s1与j-1长s2或者i-1长s1与j长的s2,所以似乎dp[i][j] = max(dp[i-1][j]+dp[i][j-1])

最长递增子序列

package main

import "fmt"

func main() {
	s1:=[]int{1,3,5,2,4,6,7,8}
	f:=make([]int,len(s1))
	f[0] = 1
	for i:=1;i<len(s1);i++{
		f[i]=1
		for j:=0;j<i;j++{
			if (s1[j]<s1[i]&&f[j]>f[i]-1){
				f[i] = f[j]+1
			}
		}
	}
	fmt.Println(f[len(s1)-1])
}

//1,2,4,6,7,8
//6个
1)f表示数组到第i个数字的时候最长的子序列,从0开始是第一个
2)循环列表,第i个开始都是1,然后当前面的有数字小于第i个,则可能是一个子序列,若第j个长度大于第i个减去本身,则f[i]=f[j]+1,选择值最大的一个
3)查询结束最大的为f[len(s1)-1]

===============================================================
最大子序列和

package main

import "fmt"

func main() {
	s1:=[]int{-6,-2,11,-4,13,5,-2}
	max:=0
	temp:=0
	for i:=0;i<len(s1);i++{
		if temp<0{
			temp = s1[i]
		}else{
			temp = temp+s1[i]
		}
		if temp>max{
			max=temp
		}
	}
	fmt.Println(max)
}

1)temp代表上一次的和,若上一次的和小于0.加上更小,换这一次的为这一次的值
2)若大于0,加上更大,则加上
3)若当次temp大于上一次的值,则max获得,最后返回max

给定两个字符串,s1和s2,让你求通过插入删除修改等操作使两个字符串相等的最小次数(距离)

package main

import "fmt"

func main() {
	s1:="messi"
	s2:="messol"
	n1:=len(s1)
	n2:=len(s2)
	dp:=make([][]int,n1+1)
	for i:=0;i<=n1;i++{
		dp[i] = make([]int,n2+1)
	}
	for i:=1;i<=n2;i++{
		dp[0][i] = i
	}
	for i:=1;i<=n1;i++{
		dp[i][0] = i
	}
	fmt.Println(dp)
	for i:=0;i<n1;i++{
		for j:=0;j<n2;j++{
			var temp int
			if s1[i] == s2[j]{
				temp = 0
			}else{
				temp = 1
			}
			dp[i+1][j+1] = min(min(dp[i][j+1]+1,dp[i+1][j]+1),dp[i][j]+temp)
		}
	}
	fmt.Println(dp[n1][n2])
}

func min(a,b int)int{
	if a<b{
		return a
	}
	return b
}

1)temp代表上一次的和,若上一次的和小于0.加上更小,换这一次的为这一次的值
2)若大于0,加上更大,则加上
3)若当次temp大于上一次的值,则max获得,最后返回max

凸多边形
https://blog.csdn.net/liufeng_king/article/details/8639376

===============================================================
合并石块问题

package main

import (
	"fmt"
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func stone(num int, arr []int) (int, int) {
	Min := make([][]int, num+1)
	Max := make([][]int, num+1)
	for i := 0; i <= num; i++ {
		Min[i] = make([]int, num+1)
		Max[i] = make([]int, num+1)
	}
	sum := make([]int, num+1)
	for i := 1; i <= num; i++ {
		sum[i] = sum[i-1] + arr[i]
	}
	for v := 2; v <= num; v++ {
		for i := 1; i <= num-v+1; i++ {
			j := i + v - 1
			Min[i][j] = 100000
			Max[i][j] = -1
			tmp := sum[j] - sum[i-1]
			for k := i; k < j; k++ {
				Min[i][j] = min(Min[i][j], Min[i][k]+Min[k+1][j]+tmp)
				Max[i][j] = max(Max[i][j], Max[i][k]+Max[k+1][j]+tmp)
			}
		}
	}
	return Min[1][num], Max[1][num]
}

func main() {
	array := []int{0, 3, 4, 3, 34, 3, 3}
	fmt.Println(stone(len(array)-1, array))
}

1)sum[i] = arr[0~i-1] + arr[i]的值
2)从第二个坐标开始,到数目num,循环
3)i从1到num-v+1,表示的是中间可能的石碓合并点
4)Min[i][j],Max[i][j]表示石碓i~j最多的,
5)k从i到j, Min[i][j] = min(Min[i][j], Min[i][k]+Min[k+1][j]+tmp) Max[i][j] = max(Max[i][j], Max[i][k]+Max[k+1][j]+tmp)

发布了212 篇原创文章 · 获赞 33 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/hello_bravo_/article/details/92070121
今日推荐