題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6017
本弱雞覺得這道題好難,看着別人的代碼理解了好久,也沒有想的太明白,還是先記錄一下把,以後再來看看,
狀態分析:
1、剩餘沒有處理的2
2、上一個2的位置
3、得到233的個數
4、付出的代價
首先要明確的是如果2與2交換或者3與3交換是沒有意義的 所以最後2的相對位置是沒有變化的,所以我們只需要從後往前處理每一個二就好了
dp[i][j][k]表示剩餘i個二沒有處理,最後一個2在位置j得到233個數爲k的最小花費
狀態轉移:從後往處理 dp[i-1][t][k+(t+2<j)] = min(dp[i-1][t][k+(t+2<j)] ,dp[i][j][k]+第i-1個2移動到位置t的花費)
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define LL long long
int dp[105][105][105]; // 第i個2放在位置j的時候消耗次數k的時候取得的最大233
void Init(int n)
{
for(int i = 0;i<n+2;i++)
{
for(int j = 0;j<n+2;j++)
{
for(int k = 0;k<50;k++)
{
dp[i][j][k] = 9999999;
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
char str[105];
int pos[105];
int tail = 0;
scanf("%d%d",&n,&m);
m/=2;
Init(n);
scanf("%s",str+1);
for(int i = 1;i<=n;i++)
{
if(str[i]=='2')
pos[++tail] = i;
}
pos[0] = 0;
pos[++tail] = n+1;
dp[tail][n+1][0] = 0;
for(int i = tail;i>1;i--)
{
for(int j = n+1;j>=1;j--)
{
for(int k = 0;k<n/3+2;k++)
{
if(dp[i][j][k]<=m)
{
for(int t = j-1;t>=1;t--)
{
dp[i-1][t][k+(t+2<j)] = min(dp[i-1][t][k+(t+2<j)],dp[i][j][k]+abs(pos[i-1]-t));
//cout << i-1 <<dp[i-1][t][k+(t+2<j)] << " " << k+(t+2<j) << endl;
}
}
}
}
}
int ans = 0;
for(int i = 1;i<=n+1;i++)
{
for(int k = 0;k<=n/3+2;k++)
{
if(dp[1][i][k]<=m)
ans = max(k,ans);
}
}
printf("%d\n",ans);
}
return 0;
}