HUST Online Judge WebBoard
Problem 1128 >> 虽然说感觉到是动态规划了,but
201803120130 @ 2019-04-18 20:40:42
[ Quote ] [ Edit ] [ Delete ] 1#
有点想法,好像不用动态规划也做的出
#include<stdio.h>
#include<stdlib.h>

int //贪心算法
Greedy_Algorithm();
//删除当前数组中被删除的代价最小的

int //动态规划
Dynamic_Programming();
//使接下来所有删除元素的代价最小

int//计算删除该元素代价
Calculate_Cost(int *a, //元素数组
int x //删除位置
);
int//删除array某个位置
Delete_Type(int *a, //被删除数组
int n, //数组长度
int x //被删除位置
);
void//输入牌
Scan(int **a,
int *pn
);
int//搜索最小代价元素
Serch_MinCost(int *a, //被搜索数组
int n, //数组长度
int *pcost//所需要的代价
);
int //搜索数值最大的元素,将其储存进temp中
Serch_MaxType(int *a,
int n,
int *temp
);
int //选择数组中代价最小的元素
Select_MinCost(int *Queue,
int q_rear,
int *temp,
int t_rear
);

int main()
{
printf("%d\n",Dynamic_Programming());
return 0;
}
int //动态规划
Dynamic_Programming()
{//删除当前数组元素删除代价最小的最大值,尽量使后面的行为代价最小
int deleted,cost,sum = 0;
int *temp,t_rear;
int *Queue,q_rear;
//输入数组
Scan(&Queue,&q_rear);

temp = (int *)malloc(sizeof(int) * q_rear);

//删除元素直至只有俩个元素位于队列
while(q_rear != 2)
{
//搜索最大值的元素,将其下标储存进temp
t_rear = Serch_MaxType(Queue,q_rear,temp);
//选取最大元素中选取代价最小的
deleted = Select_MinCost(Queue,q_rear,temp,t_rear);
cost = Queue[deleted-1]*Queue[deleted]*Queue[deleted+1];
//删除代价最小的
Delete_Type(Queue,q_rear,deleted);
q_rear--;
//将代价累加进sum中
sum += cost;
}
//退出循环将sum返回
return sum;
}
int //选择数组中代价最小的元素
Select_MinCost(int *a,
int q_rear,
int *temp,
int t_rear
)
{
int i,min;
min = a[temp[0]-1]*a[temp[0]]*a[temp[0]+1];
for(i = 0;i < t_rear-1;i++)//找到最小代价的最大值
min = ( min<a[temp[i]-1]*a[temp[i]]*a[temp[i]+1]?
min:a[temp[i]-1]*a[temp[i]]*a[temp[i]+1]);
for(i = 0;a[temp[i]-1]*a[temp[i]]*a[temp[i]+1] != min;i++);
//找到最大值下标
return temp[i];
}
int //搜索数值最大的元素,将其储存进temp中
Serch_MaxType(int *a,int n,int *temp)
{
int i,max,count = 0;
max = a[1];
for(i = 1;i < n-1;i++)
max = (max>a[i]?max:a[i]);
for(i = 1;i < n-1;i++)
if(a[i] == max)
temp[count++] = i;
return count;
}

int //贪心算法
Greedy_Algorithm()
{
int deleted,cost,sum = 0;
int *Queue,q_rear;
Scan(&Queue,&q_rear);

//删除元素直至只有俩个元素位于队列
while(q_rear != 2)
{
//搜索代价最小的
deleted = Serch_MinCost(Queue,q_rear,&cost);
//删除代价最小的
Delete_Type(Queue,q_rear,deleted);
q_rear--;
//将代价累加进sum中
sum += cost;
}
//退出循环将sum返回
return sum;
}
int//删除array某个位置
Delete_Type(int *a,int n,int x)
{
int i;
for(i = x;i < n-1;i++)
a[i] = a[i+1];
return 1;
}
int//搜索最小代价元素
Serch_MinCost(int *a,int n,int *pcost)
{
int i,min;
min = a[0]*a[1]*a[2];
for(i = 2;i < n-1;i++)
min = (min<a[i-1]*a[i]*a[i+1]?min:a[i-1]*a[i]*a[i+1]);
*pcost = min;
for(i = 1;a[i-1]*a[i]*a[i+1] != min;i++);
return i;
}
void//输入牌
Scan(int **a,int *pn)
{
int i;
scanf("%d",pn);
*a = (int *)malloc(sizeof(int) * (*pn));
for(i = 0;i < (*pn);i++)
scanf("%d",&(*a)[i]);
}
201803120130 @ 2019-04-18 20:45:27
[ Quote ] [ Edit ] [ Delete ] 2#
不要沉,寻求帮助
201803120130 @ 2019-04-18 20:46:55
[ Quote ] [ Edit ] [ Delete ] 3#
卑微死了,我觉得思路一点也没毛病,算法分析一下,感觉时间复杂度不算特别高啊,相对于枚举法,应该快了挺多了
201803120130 @ 2019-04-18 20:48:21
[ Quote ] [ Edit ] [ Delete ] 4#
另外就是,我觉得前面会影响后面啊,不满足无后效性的样子,还是我想错了
201703120121 @ 2019-04-21 13:03:16
[ Quote ] [ Edit ] [ Delete ] 5#
非常好!!!
首先讨论下贪心为什么不行。
对于题目给出的样例来说,“如果数是10 1 50 20 5,依次拿1、20、50,总分是 10*1*50+50*20*5+10*50*5=8000,而拿50、20、1,总分是1*50*20+1*20*5+10*1*5=1150。”
好像贪心策略是从大往小贪(不包含区间两头),那么再看这组数据,1 2 3 4,从大往小贪,结果为2*3*4+1*2*4=32,而从小往大贪则是1*2*3+1*3*4=18。
贪心只能保证求得局部最优解,而无法保证求得全局最优解。

那该怎么解这道题呢?

求全局最优解,想到动态规划。我看了下你的动态规划写法(贪心写法我没看),动态规划写法还是有种只考虑局部没有考虑全局的感觉,
因为当你在删除那个“最大元素中最小代价”时并没有考虑,先删除其他元素后(记这次运算结果为cost1)和再次运算删除“最大元素中最小代价”(为cost2)对整体的影响,因为删除一个元素,后面的结果就全会发生变化(你也意识到了qwq)。


动态规划算法的核心在于状态转移方程,状态转移就是当你一下子不能求得全局解的时候,可以先求出局部解,由局部解慢慢递推到全局解。
这有分治算法的思想,你应该自学过了吧(如果没的话,可以去做下oj里面《数据结构-查找与排序》里的归并排序题,这对理解分治很有帮助,再了解下归并排序求逆序数,惊人的效率,扯远了)。

比如这道题,求区间[i,j]内得分最小的。
用dp[i][j]表示i到j内得分最小的,在[i,j]内任意取一点k。
那么dp[i][k]表示i到k内得分最小,
dp[k][j]表示k到j内得分最小,可以说k,就是当可合并区间只剩3个元素时,最中间的那个。
得到dp[i][j]=dp[i][k]+dp[k][j]+arr[i]*arr[k]*arr[j];
求得分最小,状态转移方程为dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+arr[i]*arr[k]*arr[j]);
这一类dp称为区间dp,在区间内求最优解。状态转移方程有些类似(具体看求什么),之后我会再找几个题目挂上去

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e3;
const int inf=0x3f3f3f3f;

int arr[MAXN];
int dp[MAXN][MAXN];

int main() {
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>arr[i];

memset(dp,0,sizeof(dp));
for(int p=3;p<=n;p++) { //区间长度为2,最小值为0;所以先求区间长度为3,比如求1-3内区间最小,2-4 再求长度为4,如1-4区间最小,2-5,类推

for(int i=1;i<=n-p+1;i++) { //当区间长度p确定时,i可到达最右边的值;比如n=10时,p=3,那么i最大为8,因为当i==9时,比大于等于i的只有9,10两个
int j=p+i-1; //根据区间长度和区间开始位置求区间结束位置
if(j>n) break;
dp[i][j]=inf;

for(int k=i+1;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+arr[i]*arr[k]*arr[j]);
}
}
cout<<dp[1][n]<<endl;

return 0;
}
有点仓促了。
201703120121 @ 2019-04-21 13:33:57
[ Quote ] [ Edit ] [ Delete ] 6#
链接:https://pan.baidu.com/s/1vjo-4yhIwZocFJDBhI6Vew
提取码:cs5r
这两本书可用作算法入门书,其中《趣学算法》一书(作者为陈小玉教授),目前我在把题目导进去,可以去看下。
201803120130 @ 2019-04-21 19:25:25
[ Quote ] [ Edit ] [ Delete ] 7#
算法我在自学,我把数据结构学校的书、数据结构c语言描述都基本过了一遍
数据结构查找与排序的算法我基本都写完了,还有一个二叉树排序和堆排序没写,其他的基本都掌握了
递归我自我感觉应该还行
局部优解推全局优解我也了解,关键是我觉得他不满足动态规划的无后效性。可能是我还没理解题意,我再看看题目和学长的代码试试看是我哪里理解错了。
201803120130 @ 2019-04-21 19:26:02
[ Quote ] [ Edit ] [ Delete ] 8#
qwq
201803120130 @ 2019-04-21 19:48:45
[ Quote ] [ Edit ] [ Delete ] 9#
我觉得我应该知道哪里错了,我是另外一种模式的贪心算法,我去试试动态规划
201803120130 @ 2019-04-21 19:51:52
[ Quote ] [ Edit ] [ Delete ] 10#
其实我觉得4093阿克曼函数和1135点的连线总长都有动态规划的影子
201706030223 @ 2019-05-22 21:00:31
[ Quote ] [ Edit ] [ Delete ] 11#
仰望大佬