2018.02.04
补作业系列
1.合并石子
思路:
核心代码:
状态转移方程&解析:s[i]表示前i堆石子的数量总和,f[i][j]表示把第i堆石子到第j堆石子合并成一堆的最优值。
1 for ( i = n-1 ; i >= 1 ; i-- ){ 2 for ( j = i+1 ; j <= n ; j++ ){ 3 for ( k = i ; k <= j-1 ; k++ ){ 4 f[i][j] = min ( f[i][j] , f[i][k] + f[k+1][j] + s[j] -s[i-1] ); 5 } 6 } 7 } 8 输出f[1][n]
状态:AC
2.挖地雷
思路:
核心代码:
1 #include <stdio.h> 2 #include <math.h> 3 #include <string.h> 4 int main(){ 5 long f[201]={0},w[201],c[201]={0}; 6 int a[201][201]={0}; 7 long i,j; 8 long n; 9 long x,y; 10 long l,k,maxx; 11 memset(f,0,sizeof(f)); 12 memset(c,0,sizeof(c)); 13 memset(a,0,sizeof(a)); 14 scanf("%d",&n); 15 for(i=1;i<=n;i++) 16 scanf("%ld",&w[i]); 17 for(i=1;i<n;i++){ 18 for(j=i+1;j<=n;j++){ 19 scanf("%d",&x); 20 if(x==1)a[i][j]=1; 21 } 22 } 23 f[n]=w[n]; 24 for(i=n-1;i>=1;i--){ 25 l=0;k=0; 26 for(j=i+1;j<=n;j++) 27 if((a[i][j])&&(f[j]>l)){ 28 l=f[j];k=j; 29 } 30 f[i]=l+w[i]; 31 c[i]=k; 32 } 33 k=1; 34 for(j=2;j<=n;j++) 35 if(f[j]>f[k])k=j; 36 maxx=f[k]; 37 printf("%ld",k); 38 k=c[k]; 39 while(k!=0){ 40 printf(" %ld",k); 41 k=c[k]; 42 } 43 printf("\n%ld\n",maxx); 44 return 0; 45 }
状态转移方程&解析:
很明显,题目所规定的所有路径都是单向的,所以满足无后效性原则和最优化原理。设w[i]为第i个地窖所藏有的地雷数,a[i][j]表示第i个地窖与第j个地窖之间是否有通路,f[i]为从第i个地窖开始最多可以挖出的地雷数,则有如下递归式:
1 f[i]=max{ w[i]+f[j] } ( i<j<=n && a[i][j]=true ) 2 边界: f[n]=w[n]
于是就可以通过递推的方法,从后面的f(n)往前逐个找出所有的f[i],再从中找出一个最大的即为问题二的解。对于具体走的路径(问题一),可以通过一个向后的链接来实现。
状态:AC