动态规划- 【气球游戏】

题目:【气球游戏】小Q在进行射击气球的游戏,如果小Q在连续T枪中打爆了所有颜色的气球,将得到一只QQ公仔作为奖励。(每种颜色的气球至少被打爆一只)。这个游戏中有m种不同颜色的气球,编号1到m。小Q一共有n发子弹,然后连续开了n枪。小Q想知道在这n枪中,打爆所有颜色的气球最少用了连续几枪?
输入描述:
第一行两个空格间隔的整数数n,m。n<=1000000 m<=2000
第二行一共n个空格间隔的整数,分别表示每一枪打中的气球的颜色,0表示没打中任何颜色的气球。
输出描述:
一个整数表示小Q打爆所有颜色气球用的最少枪数。如果小Q无法在这n枪打爆所有颜色的气球,则输出-1
示例
输入:
12 5
2 5 3 1 3 2 4 1 0 5 4 3
输出:
6

二、思路:

1.暴力求解:冒泡排序的方式遍历击中气球序列arr_ball[2000],对每个子串i...j范围进行判断是否击中所有颜色气球,全部击中所有颜色则赋值击中次数shut_cnt。复杂度o(n^3)

2.对问题进行抽象:个人认为分两步

1)找出所有包含1~m数字的子数组序列,这种序列的特点是子数组的和大于等于 (1+...+m)且包含1...m数字,可以抽象成求数组序列子段和大于某一阈值问题。

2)找出子数组长度最短的序列长度。

 

暴力求解代码c++: 

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
// 返回是否击中所有颜色,赋值击中次数shut_cnt 
bool loop_m(int i,int j ,int arr_ball[],int m,int &shut_cnt)
{
    int sum_m=0,is_shut=1;
	int tmp_m[200]={0};
	for(int k=i;k<=j;k++)
	{
       //没有击中任何颜色,设计次数+1
	   if(arr_ball[k]==0 ) sum_m=1;
	   else tmp_m[arr_ball[k]-1]+=1;
	}
	for(int j=0;j<m;j++)

	{  
	   //命中次数
		sum_m+=tmp_m[j];  

	   //是否所有颜色命中,如果有遗漏则,则该组命中次数设置为0

	   if(tmp_m[j]==0) is_shut=0;

	}

shut_cnt+=sum_m;


return is_shut!=0 ? true : false ;

}
int is_vector(int n,int m, int arr_ball[])
{

	 int i=0,j=0,cur_min=0,min=10000;
    //for(int i=0;i<m;i++) i+=tmp_m[i]; //memset(&tmp_m,0,sizeof(tmp_m));
    for( i=0 ;i<n-1;i++)
    {
	  for(j=i+1;j<n;j++)
	  {
          //长度>=m的子序列
		  if(j-i+1>=m)
		  {    //当前击中次数
		       cur_min=0;
               //子序列中是否有满足击中所有颜色气球
			   if(loop_m(i,j,arr_ball,m,cur_min)==true)
			   {
				   if(cur_min<min)
				   min=cur_min;}
			   }
		  }

	  }

    }
	return (min >=m && min!=10000)? min : -1 ;

}

int main() {
    int n,m,arr_ball[2000];
    cin >> n>> m;
    for(int i=0;i<n;i++) cin>>arr_ball[i];
    cout << is_vector(n,m,arr_ball) << endl;
}

结果:

测试用例1

12 5
2 5 3 1 3 2 4 1 0 5 4 3

结果:

测试用例2:

12 5
2 5 3 1 4 2 4 1 0 5 4 3

结果:

测试用例3:

12 5
2 5 3 3 4 2 4 3 0 5 4 3

结果:

 

结果:

   若使用子段和问题的方法,就是动态规划问题,复杂度可降为O(n)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值