题意:
Vasya有n天可以安排,0表示一定要休息,1表示可以去比赛或者休息,2表示可以去健身或者休息,3表示可以去比赛或者健身或者休息,且不能连续的两天进行竞赛或者健身,问他最少需要休息几天。
思路:
枚举。若出现3,判断下前一个是1或者2,如果是则将3置为2或者1,如果不是不用管,若出现连续的两个1或者2将第二个置为0。
#include<cstdio>
const int MAX=105;
int n,a[MAX];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int l=1;
while(a[l]==3){
l++;
}
for(int i=l+1;i<=n;i++){
if(a[i]==3){
if(a[i-1]!=3) a[i]=3-a[i-1];
}
else{
if(a[i]==a[i-1]) a[i]=0;
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(!a[i]) ans++;
}
printf("%d\n",ans);
return 0;
}
DP。正解。
dp[i][0]表示第i天是0的最小休息天数。
dp[i][1]表示第i天是1的最小休息天数。
dp[i][2]表示第i天是2的最小休息天数。
转移方程:
dp[i][0]=min(min(dp[i-1][0],dp[i-1][1]),dp[i-1][2])+1;
dp[i][1]=min(min(dp[i-1][0],dp[i-1][2]),dp[i-1][1]+1);
dp[i][2]=min(min(dp[i-1][0],dp[i-1][1]),dp[i-1][2]+1);
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX=105;
int n,a[MAX],dp[MAX][5];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
memset(dp,INF,sizeof(dp));
dp[1][0]=1;
if(a[1]==1) dp[1][2]=0;
if(a[1]==2) dp[1][1]=0;
if(a[1]==3) dp[1][1]=dp[1][2]=0;
for(int i=2;i<=n;i++){
dp[i][0]=min(min(dp[i-1][0],dp[i-1][1]),dp[i-1][2])+1;
if(a[i]==1) dp[i][2]=min(min(dp[i-1][0],dp[i-1][1]),dp[i-1][2]+1);
if(a[i]==2) dp[i][1]=min(min(dp[i-1][0],dp[i-1][2]),dp[i-1][1]+1);
if(a[i]==3){
dp[i][2]=min(min(dp[i-1][0],dp[i-1][1]),dp[i-1][2]+1);
dp[i][1]=min(min(dp[i-1][0],dp[i-1][2]),dp[i-1][1]+1);
}
}
printf("%d\n",min(min(dp[n][0],dp[n][1]),dp[n][2]));
return 0;
}