题意:每台电脑价钱一样,买一台要c元,买了要包养(保养),m(1,2)就是第一年和第二年一起的保养花费。
电脑肯定每年都要用,怎么取舍是买新电脑,还是保养旧电脑,找出最小花费。
测试数据分析:一台电脑3元,第一年m(1,1)=5,要买还嘚保养,花8元,第二年,用老电脑实际只需要花2元保养即可,买新的要6+3元,花10元,然后第三年,买新的8-6+3,总共花15元,是不是,答案不是,这个思路乱了,使用m(i,j)里的数据是有前提的,就是沿用旧的才有意义,你之前拿的一号机,怎么能去找保养二号机的地方保养呢,更不会说给你更便宜的价格了,应该是第二年买新的8+3+6=17,第三年17+8-6=19。
思路:每年只有两种情况,买新的,用旧的,正如上面所说,要调用后面的m(i,j),必须一开始它刚出的时候就买,分多路线走,一条路线对应一年必须买新的,每多一年只是多一条路线,因为不可能再去买原先出现过的电脑,每年都新出一台电脑,最终判断最少花费的路线即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define inf INT_MAX
//#define INF 0x3f3f3f3f 细节,为什么这么设?
using namespace std;
int a[1001][1001];
int num[1001][1001];
int main()
{
int c,n,minn;
while(scanf("%d",&c)!=EOF){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
scanf("%d",&a[i][j]);
num[i][j]=a[i][j]-a[i][j-1];
}
}
for(int j=2;j<=n;j++){//从第二年开始
minn=inf;
for(int i=1;i<=j;i++){//之前的路线+新路线
if(j==i){
for(int k=1;k<i;k++)
minn=min(minn,num[k][j-1]);//去年花最少的时候
num[i][j]+=minn+c;
continue;
}
num[i][j]+=num[i][j-1];//旧路线跟进
}
}
minn=inf;
for(int i=1;i<=n;i++)
minn=min(minn,num[i][n]);
printf("%d\n",minn+c);
}
return 0;
}
细节问题:
#define INF 0x3f3f3f3f
为什么设无穷大要设成这个样子?因为0x3f3f3f3f的十进制是1061109567,也就是10^9级别的(和0x7fffffff(32-bit int的最大值)一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
最大好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a)),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数了,因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f 所以要把一段整型数组全部置为无穷大,我们只需要 memset(a,INF,sizeof(a))。
并不清楚为什么,在电脑上只需要iostream,网上编译要加algorithm。
网上的说法就更多了,什么cstdlib,windows.h,windef.h了,麻烦,不如自己宏定义。
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
另外,min,max是可以重载的,就像这样
string min(string a,string b)
{
if(a.compare(b)>0)
return a;
else
return b;
}
int min(int a,int b)
{
return a+b;
}
很有意思