TopCoder SRM 589 Div2 第2题

类型:DP  难度:2

题意:一堆齿轮两两相邻排成一圈,给出每个齿轮旋转方向,齿轮首尾相连,即n个齿轮,0和n-1相邻,齿轮与左右相邻的齿轮方向都相反才能转动,去掉一个齿轮,左右齿轮不看成相邻,问至少去掉几个齿轮,才能保证剩余齿轮都能按照给定方向转动。齿轮方向用L,R表示。

 

分析:dp问题,用dp[i][0]存储去掉第i个齿轮,0到i总共去掉的齿轮数最小值,dp[i][1]表示不去掉第i个齿轮,0到i总共去掉的齿轮数最小值

递推公式:dp[i][0] = min(dp[i-1][0],dp[i-1][1])+1

若当前齿轮与前一个方向不同:dp[i][0] = min(dp[i-1][0],dp[i-1][1])

否则:dp[i][1] = dp[i-1][0]

最后min(dp[n-1][0],dp[i-1][1])即为所求

但是由于齿轮是首尾相连的,所以要考虑最后一个齿轮与第一个齿轮是否是相同方向,用f[i][0]记录dp[i][0]取最小值时,第1个齿轮是否被去掉;f[i][1]记录dp[i][1]取最小值时,第1个齿轮是否被去掉

最后,若最后一个和第一个方向相同且dp[n-1][1]取最小时第一个齿轮存在,则dp[n-1][1]++,即还需去掉第一个齿轮才能转动。

代码如下:

 

#include<string>
#include<vector>
#include<cstring>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;

#define MIN(x,y) (x)<(y)?(x):(y)

const int MAX = 55;
class GearsDiv2
{
	public:		
		int dp[MAX][2];
		bool first[MAX][2]; 
		int getmin(string Directions)
		{
			memset(dp,0,sizeof(dp));
			memset(first,0,sizeof(first));
			
			int n = Directions.length();
			
			dp[0][0] = 1;
			dp[0][1] = 0;
			first[0][0] = 1;
			first[0][1] = 0;
			for(int i=1; i<n; i++)
			{
				if(dp[i-1][0] < dp[i-1][1])
				{
					dp[i][0] = dp[i-1][0]+1;
					first[i][0] = first[i-1][0];
				}
				else if(dp[i-1][0] > dp[i-1][1])
				{				
					dp[i][0] = dp[i-1][1]+1;
					first[i][0] = first[i-1][1];
				}
				else 
				{
					dp[i][0] = dp[i-1][1]+1;
					first[i][0] = first[i-1][1] | first[i-1][0];
				}
				
				if(Directions[i]!=Directions[i-1])
				{
					dp[i][1] = dp[i][0] - 1;
					first[i][1] = first[i][0];
				}
				else
				{
					dp[i][1] = dp[i-1][0];
					first[i][1] = first[i-1][0];
				}
			}
			if(n>2)
			{
				if(Directions[n-1]==Directions[0] && !first[n-1][1])
				{
					dp[n-1][1]++;
				}
			}
			
			return MIN(dp[n-1][0],dp[n-1][1]);
		}
};

你可能感兴趣的:(C++,dp,topcoder)