题目大意:给你n个数字,给你k次两两交换数字的机会
问你前m个数字的和最小可能是多少?
思路:dp
首先f[i][j]表示前i个数有j次交换的和
a[i]表示第n个数字的值
我们可以利用一个变量k表示第k个数
这样就可以利用k-i-1表示两两交换位置
注意i要从k-1开始到0,不然会有后效性
那么可以写出式子f[i+1][j+k-i-1]=min(f[i][j+k-i-1],f[i][j]+a[k])
具体参照代码注释
AC代码:
#include <iostream> #include <string.h> using namespace std; int a[155]; int f[155][155*155]; int main() { int n,m,k; memset(f,0x3f3f3f,sizeof(f)); int ans=1010010100;//因为最多就150个一百万的数据,int就够了 cin>>n>>m>>k; for(int i=1;i<=n;i++)cin>>a[i]; f[0][0]=0; for(int k=1;k<=n;k++){ for(int i=k-1;i>=0;i--){//从k-1开始是为了防止后效性 //不然f[i][j]变动之后之后的f[i+1][j]会受新的f[i][j]的影响 for(int j=0;j<=k*i;j++){ f[i+1][j+k-i-1]=min(f[i+1][j+k-i-1],f[i][j]+a[k]); //k-i-1表示移动距离 } } } for(int j=0;j<=min((n*(n)),k);j++){//最多移动题目要求的k次或者n*n次 ans=min(f[m][j],ans); } cout<<ans<<endl; return 0; }