【贪心】Codeforces698A-Vacations

哎,这道题昨天上午学长讲过思路,按照学长的想法写好了程序就是不AC,真是¥%#……%&了,狠在那里想贪心呢,后来看了其他菊苣的思路发现还要用到动态规划……完全没有听说过好吧!?后来又搜了搜动态规划,看看大神的代码,搞了一上午才搞明白。。。不说废话了,先上题!

【题目】


Vacations
Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Description(描述)

Vasya has n days of vacations! So he decided to improve his IT skills and do sport. Vasya knows the following information about each of this n days: whether that gym opened and whether a contest was carried out in the Internet on that day. For the i-th day there are four options:

  1. on this day the gym is closed and the contest is not carried out;
  2. on this day the gym is closed and the contest is carried out;
  3. on this day the gym is open and the contest is not carried out;
  4. on this day the gym is open and the contest is carried out.

On each of days Vasya can either have a rest or write the contest (if it is carried out on this day), or do sport (if the gym is open on this day).

Find the minimum number of days on which Vasya will have a rest (it means, he will not do sport and write the contest at the same time). The only limitation that Vasya has — he does not want to do the same activity on two consecutive days: it means, he will not do sport on two consecutive days, and write the contest on two consecutive days.

Input(输入要求)

The first line contains a positive integer n (1 ≤ n ≤ 100) — the number of days of Vasya's vacations.

The second line contains the sequence of integers a1, a2, ..., an (0 ≤ ai ≤ 3) separated by space, where:

  • ai equals 0, if on the i-th day of vacations the gym is closed and the contest is not carried out;
  • ai equals 1, if on the i-th day of vacations the gym is closed, but the contest is carried out;
  • ai equals 2, if on the i-th day of vacations the gym is open and the contest is not carried out;
  • ai equals 3, if on the i-th day of vacations the gym is open and the contest is carried out.

Output(输出要求)

Print the minimum possible number of days on which Vasya will have a rest. Remember that Vasya refuses:

  • to do sport on any two consecutive days,
  • to write the contest on any two consecutive days.

Sample Input(样例输入)

Input
4
1 3 2 0
Output
2
Input
7
1 3 3 2 1 2 3
Output
0
Input
2
2 2
Output
1

【题目解释】

mdzz又是英文题!题目说有一个少年放假了闲着没事干,每天有三种活动可以选择:去健身房,参加比赛,在家呆着。
ai = 0,表示第i天健身房不开门这天也没有比赛可以参加;
ai = 1,表示第i天有比赛但是健身房关门;
ai = 2,表示第i天健身房开门但是没有比赛;
ai = 3,表示第i天健身房开门,也有比赛可以参加。

但是有要求:任意连续的两天不能连续健身或比赛。要求出这个boy在这个假期里最少能在家呆上几天(就是尽可能不在家呆着)。

第一行输入假期天数,第二行通过0123分别代表每天能参加的活动情况,对应n个数字。第三行输出答案。


【解题思路】

动态规划:简单来说就是根据前面已有的数据来推后面,这种方法要求后面的东西不能影响到前面。

贪心:只考虑眼前的最优解。

这里贪心算法跟动态规划结合,我们设定数组a[102](题目上说了假期最多100天,多设两个安全点)来储存每天能参加的活动(0123),再设置一个dp[ i ][ 4 ]的二维数组,dp[ i ][ 0 ]中储存的事如果第i天boy做了第0件事,那么截止至第i天,这个boy已经在家呆了的天数。我们设置dp[ 0 ][ 0 ]dp[ 0 ][ 1 ]dp[ i ][ 2 ]dp[ 0 ][ 3 ]为0,因为第0天啥也不是没什么意义,其它的元素全部初始化为一个很大的数(这个数值一定要超过假期总天数,后面会解释)。


这样到第i天时,如果这天活动是第0号活动,那么今天必然呆在家,那么dp[ i ][ 0 ]就是直到昨天那一天一共休息的最少天数加1,即dp[ i ][ 0 ]为dp[ i-1 ][ 0 ]dp[ i-1 ][ 1 ]dp[ i-1 ][ 2 ]dp[ i-1 ][ 3 ]中的最小值加1,可能有人会疑问,dp[ i ][ 1 ]dp[ i ][ 2 ]dp[ i ][ 3 ]的值还没有设置啊,它们初始化之后数值不是很大吗?我们知道这个时候我们没办法执行123号情况,那么这三个数就成了无用值,不在我们后面计算天数的范围之内了,设置为大于假期的数,在最后考虑的时候就能直接发现并舍去了,执行后面123号操作时,没有考虑的dp[ i ][ j ]值也是这个原理。

如果是一号活动,就有两种情况: 执行0或者1, 如果执行0,此时dp[ i ][ 0 ]的值同第0号活动计算的方式相同,即dp[ i ][ 0 ]就是昨天一天休息的最少天数加1,若执行1,那么dp[ i ][ 1 ](注意是dp[ i ][ 1 ]不是dp[ i ][ 0 ]!)就等于直到昨天那一天一共休息了的最少天数(此时不在家所以不加1),即dp[ i ][ 1 ]为dp[ i-1 ][ 0 ]dp[ i-1 ][ 2 ]dp[ i-1 ][ 3 ]中的最小值(这里没有出现dp[ i-1 ][ 1 ],因为他要做的活动不会跟前一天的一样!);2号活动时方式同一号,三号活动是1号和2号的综合,即3号活动时,他可以选择去做0、1、2中的任何一种,计算这三种情形下的天数就行了,方式跟前面一样。


这样直到最后的第n天时,会出现如果此时选择0、1、2、3号活动时,休息的总天数。这样把p[ n ][ 0 ]、dp[ n ][ 1 ]、dp[ n ][ 2 ]三个数一比较,找到其中最小值就是我们要的答案了~这个理解起来确实很难,自己可以动手画一下,思路就会比较清晰了。按照上面的分析再看一看下面的代码,应该就好理解了。


【代码】

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
using namespace std;
int main()
{
	int a[102]={0};
	int n;
	while(~scanf("%d",&n))
	{
		int ans=0;
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		int dp[102][4];
		memset(dp,1,sizeof(dp));
		dp[0][0]=dp[0][1]=dp[0][2]=dp[0][3]=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]==0)
			{
				dp[i][0]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1;
			}
			if(a[i]==1)
			{
				dp[i][0]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1;
				dp[i][1]=min(dp[i-1][0],dp[i-1][2]);
			}
			if(a[i]==2)
			{
				dp[i][0]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1;
				dp[i][2]=min(dp[i-1][0],dp[i-1][1]);
			}
			if(a[i]==3)
			{
				dp[i][0]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1;
				dp[i][1]=min(dp[i-1][0],dp[i-1][2]);
				dp[i][2]=min(dp[i-1][0],dp[i-1][1]);
			}
		}
		ans=min(dp[n][0],min(dp[n][1],dp[n][2]));
		printf("%d\n",ans);	
	}
}
     
     
    
    
   
   





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值