**3-1 独立任务最优调度问题
二维数组建立:
dp[i][j] 表示完成i个任务,机器A工作时间为j时,机器B工作的时间。
递推公式如下:
dp[i][j] = min(dp[i-1][j]+b[i],dp[i-1][j-a[i]])
示例:
输入:
6
2 5 7 10 5 2
3 8 4 11 3 4
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
//独立任务最优调度问题
int main()
{
int n;
cin>>n;
int a[101];
int b[101];
int sum = 0;
int dp[101][10001];
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
for(int i=1; i<=n; i++)
{
cin>>b[i];
}
memset(dp,0,sizeof(dp));
// 假设dp[i][j]为完成I个任务时机器工作的时间为J 时B机器工作的时间
for(int i=1; i<=n; i++)
{
sum+=a[i];
for(int j=0; j<=sum; j++)
{
dp[i][j] = dp[i-1][j]+b[i];
if(j>=a[i])
{
dp[i][j] = min(dp[i-1][j]+b[i], dp[i-1][j-a[i]]);
}
}
}
int minn = inf;
for(int i=0; i<=sum; i++)
{
int t = max(i,dp[n][i]);
minn = min(minn,t);
}
cout<<minn<<endl;
return 0;
}
**3-2 最优批处理问题:
解题思路:
dp[i]表示区间[i,n]上最小总费用
递推公式:
在区间 [i,n] 选一点 j
则dp[i] = min(dp[i],dp[j]+(s+t[i]+t[i+1]+…+t[j-1]) *(f[i]+f[i+1]+…+f[n]))
示例1:
输入:
5
1
1 3
3 2
4 3
2 3
1 4
输出:
153
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-2 最优批处理问题
int main()
{
int n,s;
int t[101],f[101];
//dp[i] = min(dp[i],dp[j]+(s+t[i]...t[j-1])*(f[i]+..+f[n]))
int t_sum[101];
int f_sum[101];
int dp[101];
memset(t_sum,0,sizeof(t_sum));
memset(f_sum,0,sizeof(f_sum));
memset(dp,inf,sizeof(dp));
cin>>n>>s;
for(int i=1; i<=n; i++)
{
cin>>t[i]>>f[i];
}
for(int i=n;i>=1;i--)
{
t_sum[i] = t_sum[i+1] + t[i];
f_sum[i] = f_sum[i+1] + f[i];
}
dp[n+1] = 0;
for(int i=n;i>=1;i--)
{
for(int j=i+1; j<=n+1; j++)
{
int sum_t = s + t_sum[i] - t_sum[j];
int sum_f = f_sum[i];
dp[i] = min(dp[i],dp[j]+sum_t*sum_f);
}
}
cout<<dp[1]<<endl;
return 0;
}
Sample
Input
4
4 4 5 9
Output
43
54
参考代码:
链接: (注释版代码)
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-3 石子合并问题
int main()
{
int n;
int a[202];
int sum[202];
int dpmin[202][202];
int dpmax[202][202];
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
a[i+n] = a[i];
}
memset(sum,0,sizeof(sum));
memset(dpmin,inf,sizeof(dpmin));
memset(dpmax,0,sizeof(dpmax));
for(int i = 1; i<=2*n ;i++)
{
sum[i] = sum[i-1] + a[i];
dpmin[i][i] = 0;
}
for(int key = 1; key<n; key++)
{
for(int i=1; i+key<2*n && i < 2*n; i++)
{
int j = i + key;
for(int k=i; k<j; k++)
{
dpmin[i][j] = min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]+sum[j]-sum[i-1]);
dpmax[i][j] = max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]+sum[j]-sum[i-1]);
}
}
}
int minn = inf;
int maxx = 0;
for(int i=1; i<=n; i++)
{
minn = min(minn,dpmin[i][i+n-1]);
maxx = max(maxx,dpmax[i][i+n-1]);
}
cout<<minn<<endl;
cout<<maxx<<endl;
return 0;
}
3-4 数字三角形问题
示例1:
输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出:
30
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-4 数字三角形问题
int main()
{
int n;
int dp[101][101];
memset(dp,0,sizeof(dp));
cin>>n;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=i; j++)
{
cin>>dp[i][j];
}
}
for(int i=n-1; i>=1; i--)
{
for(int j=i; j>=1; j--)
{
dp[i][j] = dp[i][j] + max(dp[i+1][j],dp[i+1][j+1]);
}
}
cout<<dp[1][1]<<endl;
return 0;
}
3-5 乘法表问题:
示例1:
输入:
bbbba
输出:
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-5 乘法表问题
int main()
{
int dp[101][101][3];
string s;
cin>>s;
int n = s.size();
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
if(s[i-1] == 'b') dp[i][i][1] = 1;
if(s[i-1] == 'a') dp[i][i][0] = 1;
if(s[i-1] == 'c') dp[i][i][2] = 1;
}
//dp[i][j][0] 表示区间(i,j)上表达式的值为0的不同加括号方法数
for(int op=1; op<n; op++)
{
for(int i=1; i+op<=n; i++)
{
int j = i + op;
for(int k=i; k<=j; k++)
{
dp[i][j][0] += dp[i][k][0]*dp[k+1][j][2] + dp[i][k][1]*dp[k+1][j][2]+ dp[i][k][2]*dp[k+1][j][0];
dp[i][j][1] += dp[i][k][0]*dp[k+1][j][0] + dp[i][k][0]*dp[k+1][j][1]+ dp[i][k][1]*dp[k+1][j][1];
dp[i][j][2] += dp[i][k][1]*dp[k+1][j][0] + dp[i][k][2]*dp[k+1][j][1]+ dp[i][k][2]*dp[k+1][j][2];
}
}
}
cout<<dp[1][n][0]<<endl;
return 0;
}
3-6 租用游艇问题:
输入:
3
5 15
7
输出:
12
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-6 租用游艇问题
int main()
{
int n;
int r[100][101];
int dp[100][100];
cin>>n;
memset(dp,inf,sizeof(dp));
for(int i=1; i<n; i++)
{
for(int j = i+1; j <=n; j++)
{
cin>>r[i][j];
dp[i][j] = r[i][j];
}
}
for(int i=1; i<=n; i++)
{
dp[i][i] = 0;
}
//dp[100][100];
for(int op = 1; op<n; op++)
{
for(int i=1; i+op<=n; i++)
{
int j = i+op;
for(int k =i; k<j; k++)
{
dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]);
}
}
}
for(int i=1; i<n; i++)
{
for(int j=i+1; j<=n; j++)
{
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
cout<<dp[1][n]<<endl;
return 0;
}
3-7 汽车加油行驶问题
输入:
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
输出:
12
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-7 汽车加油行驶问题
int N,K,A,B,C;
int a[100][100];
int dx[4] = {-1,0,1,0};
int dy[4] = {0,-1,0,1};
int dp[100][100]; //(1,1) 到(i,j)的最少费用
int dpk[100][100]; //(1,1) 到(i,j)的步数记录
int nk;
int main()
{
cin>>N>>K>>A>>B>>C;
for(int i=1; i<=N ;i++)
{
for(int j=1; j<=N; j++)
{
cin>>a[i][j];
}
}
for(int i=1; i<=N; i++)
{
for(int j=1; j<=N; j++)
{
dp[i][j] = inf;
dpk[i][j] = K;
}
}
dp[1][1] = 0; dpk[1][1] = K;
for(int i=1; i<=N; i++)
{
for(int j=1; j<=N; j++)
{
if(i == 1 && j == 1)
{
continue;
}
int minmoney = inf ,minstep;
int tepmoney ;
int tepstep;
for(int k = 0; k < 4; k++)
{
int ti = i + dx[k];
int tj = j + dy[k];
if(ti<1 || ti>N || tj<1 || tj >N)
{
continue;
}
tepmoney = dp[ti][tj];
tepstep = dpk[ti][tj] - 1;
//条件2
if(ti>i || tj>j)
{
tepmoney += B;
}
// 条件3
if(a[i][j])
{
tepmoney += A;
tepstep = K;
}
//条件4
if(a[i][j] == 0 && tepstep == 0 && (i != N || j != N))
{
tepmoney += A+C;
tepstep = K;
}
//
if(minmoney > tepmoney)
{
minmoney = tepmoney;
minstep = tepstep;
}
}
if(dp[i][j] > minmoney)
{
dp[i][j] = minmoney;
dpk[i][j] = minstep;
}
}
}
cout<<endl;
for(int i=1; i<=N; i++)
{
for(int j=1; j<=N; j++)
{
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
cout<<dp[N][N]<<endl;
return 0;
}
3-8 最小m段和问题
输入:
7 3
34 67 23 45 56 14 24
输出:
101
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-8 最小m段和问题
int main()
{
int n,m;
int a[100];
int sum[100];
int dp[100][100];
cin>>n>>m;
for(int i=1; i<=n; i++)
{
cin>>a[i];
dp[i][1] = dp[i-1][1] + a[i];
}
//dp[i][j] 表示区间(1,i)分为j段时的最小和问题
for(int i=2; i<=n; i++)
{
for(int j=2; j<=m&&j<=i; j++)
{
dp[i][j] = inf;
for(int k=2; k<i; k++)
{
int temp = max(dp[k][j-1],dp[i][1] - dp[k][1]);
dp[i][j] = min(dp[i][j],temp);
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
3-9 圈乘运算问题
3-10 最大长方体问题
输入:
3 3 3
0 -1 2
1 2 2
1 1 -2
-2 -1 -1
-3 3 -2
-2 -3 1
-2 3 3
0 1 3
2 1 -3
输出:
14
参考代码:
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
// 3-10 最大长方体问题
int m,n,p;
int mp[51][51][51];
int maxsum_1D(int c[])
{
int flag = 0,sum = 0;
for(int i=1; i<=p; i++)
{
if(flag>0)
{
flag += c[i];
}
else
{
flag = c[i];
}
if(flag > sum)
{
sum = flag;
}
}
return sum;
}
int maxsum_2D(int b[][51])
{
int c[51];
int maxsum,sum=0;
for(int i=1; i<=n; i++)
{
for(int tp =1; tp<=p; tp++)
{
c[tp] = 0;
}
for(int j=i; j<=n; j++)
{
for(int tp = 1; tp<=p; tp++)
{
c[tp] += b[j][tp];
}
maxsum = maxsum_1D(c);
if(maxsum > sum)
{
sum = maxsum;
}
}
}
return sum;
}
int maxsum_3D()
{
int b[51][51];
int maxsum,sum=0;
for(int i=1; i<=m; i++)
{
for(int tn = 1; tn<=n; tn++)
{
for(int tp=1; tp<=p; tp++)
{
b[tn][tp] = 0;
}
}
for(int j=i; j<=m; j++)
{
for(int tn=1; tn<=n; tn++)
{
for(int tp=1; tp<=p; tp++)
{
b[tn][tp] += mp[j][tn][tp];
}
}
maxsum = maxsum_2D(b);
if(sum < maxsum)
{
sum = maxsum;
}
}
}
return sum;
}
int main()
{
cin>>m>>n>>p;
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=p;k++)
{
cin>>mp[i][j][k];
}
}
}
cout<<maxsum_3D()<<endl;
return 0;
}