动态规划ZZNU-OJ- 2054 : 油田
Posted 好好学习,天天向上
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划ZZNU-OJ- 2054 : 油田相关的知识,希望对你有一定的参考价值。
2054 : 油田
(一个神奇的功能:点击上方文字进入相应页面)
时间限制:1 Sec 内存限制:32 MiB
提交:49 答案正确:6
题目描述
在太平洋的一片海域,发现了大量的油田!
为了方便开采这些能源,人们将这些油田从1到n进行编号,
人们在开采这些油田时,有三种开采方式,分别为方式A,方式B,方式C。
用不同的方式去开采这些油田所消耗的资金不同,为了防止共振导致的油井坍塌,相邻编号的油田不能使用同一种开采方式。
我们希望你求出开采这n个油田所需要消耗的最小资金,并输出开采每个油田所采用的方式。
输入
先输入一个整数T(0 < T <= 100),代表有T组测试数据。对于每组数据,第一行输入一个正整数n(n<1000)代表油田数目,
接下来n行,每一行包含三个整数。第i(2 <= i <= n+1)行的这三个数代表着开采编号为i-1的油田分别采用A,B,C三种方式开采所消耗的资金。
输出
对于每一组测试样本,先输出样本编号,接下来输出一个整数,代表着开采这n个油田所需要消耗的最小资金,然后按编号从小到大的顺序输出开采每个油田所采用的方式。每一组测试样本的输出占一行。
样例输入
复制
1 2 4 8 3 2 1 4
样例输出
复制
Case 1: 4 CB
提示
看着像是搜索题目,但是时间复杂度太大了,最坏的情况会严重超时!如下:
#include <iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h> using namespace std; #define N 1009 const int inf=0x3f3f3f3f; int ans,n,tem[N],road[N],cost[N][4]; //tem中 1A ,2B ,3C void factroad() { int i,j,k; for(i=1;i<=n;i++) road[i]=tem[i]; return ; } void dfs(int sum,int step) //step表示当前! { if(step==n+1) { if(ans>sum) { ans=sum;factroad(); } return ; } for(int i=1;i<=3;i++) //当前step的三种选择 { if(i!=tem[step-1]) { tem[step]=i; dfs(sum+cost[step][i],step+1); } } } int main() { int i,j,k,m,T,cas=0; scanf("%d",&T); while(T--) { scanf("%d",&n); //memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) scanf("%d%d%d",&cost[i][1],&cost[i][2],&cost[i][3]); ans=inf; dfs(0,1); printf("Case %d: %d ",++cas,ans); for(i=1;i<=n;i++) printf("%c",‘A‘+road[i]-1); printf("\n"); } return 0; }
该题正解,如下:
#include <iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h> using namespace std; #define N 1009 const int inf=0x3f3f3f3f; int sum; //保存最终最小和 int ans[N]; //ans数组记录最优答案路径 int n,c[N][4]; // c数组中c[i][j]表示第i个油田的第j种开采方式的花费 int dp[N][4]; //dp数组用于动态规划查找最优解; //dp[i][j]表示第i个油田采用第j种开采方式时,整个1--i个油田需要的最小开销总和 int pre[N][4]; //pre前缀数组用于保存dp过程中的路径 void fact(int x,int y) //输出路径到ans数组里 { sum=dp[x][y]; while(x>=1) { ans[x-1]=pre[x][y]; y=pre[x][y]; x--; } } void test(int n){ //简单的调试函数 /* for(int i=1;i<=n;i++) printf("%3d",i); printf("\n");*/ for(int i=1;i<=n;i++) { printf("i%d: ",i); for(int j=1;j<=n;j++) printf("%3d",dp[i][j]); printf("\n"); } } int main() { int i,j,k,m,T,cas=0; scanf("%d",&T); while(T--) { memset(c,0,sizeof(c)); //这里很重要,C++里数组不赋初值!在下面程序中会访问到c[n+1][]数组里的数 scanf("%d",&n); //memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) scanf("%d%d%d",&c[i][1],&c[i][2],&c[i][3]); memset(dp,0,sizeof(dp)); //dp[0][]数组里的数会用到 for(i=1;i<=n+1;i++) { for(j=1;j<=3;j++) // { if(j==1) { dp[i][j]=c[i][j]+min(dp[i-1][2],dp[i-1][3]); if(dp[i-1][2]>dp[i-1][3]) //记录路径,这个没法同上一步用min() pre[i][j]=3; //这里歪打正着了,存在相等时要选择编号小的记录入路径,不然会出错 else pre[i][j]=2; } else if(j==2) { dp[i][j]=c[i][j]+min(dp[i-1][1],dp[i-1][3]); if(dp[i-1][1]>dp[i-1][3]) pre[i][j]=3; else pre[i][j]=1; } else { dp[i][j]=c[i][j]+min(dp[i-1][1],dp[i-1][2]); if(dp[i-1][1]>dp[i-1][2]) pre[i][j]=2; else pre[i][j]=1; } } } int minn=min(dp[n+1][1],min(dp[n+1][2],dp[n+1][3])); //找到最小值 if(minn==dp[n+1][1]) fact(n+1,1); else if(minn==dp[n+1][2]) fact(n+1,2); else fact(n+1,3); printf("Case %d: %d ",++cas,sum); for(i=1;i<=n;i++) printf("%c",ans[i]+‘A‘-1); printf("\n"); // test(n); } return 0; }
以上是关于动态规划ZZNU-OJ- 2054 : 油田的主要内容,如果未能解决你的问题,请参考以下文章
光学基于matlab迈克尔逊干涉仪动态仿真含Matlab源码 2054期