ZOJ_Painting A Board 状态DP

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1424

题意:给一面墙刷漆,要求刷下当前墙的时候,在其上面的墙必须都要已经刷完了。 求刷子换颜色的最少次数。

算法:状态DP。

状态转移方程:dp[i][j] = dp[k][j'] + 1。dp[i][j]表示在状态为j的情况下,最后一次刷的是i区域的最少转化次数。本题需要特别注意的就是需要考虑在当前状态下,最后一次刷i墙是否合法,即需要判断i墙上面的强是否都已经刷过了。其他的就和一般的状态DP一样了。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int N;
struct Node{
	int uly,ulx,lry,lrx ;
	int color ;	
	friend bool operator <(const Node& a,const Node& b)
	{
		if(a.uly == b.uly)	return a.ulx < b.ulx ;
		else	return a.uly < b.uly ;	
	}
}block[16];

int dp[16][1<<15];

bool up(int k,int i)			//判断k区域是否是在i区域的上方(即是否要求在刷i区域之前必须先刷完k区域) 
{
	if(block[k].lry<=block[i].uly)			//注意:坐标原点是在左上角,因此在上面的要更小 
	{
		if(block[k].ulx>=block[i].lrx || block[k].lrx<=block[i].ulx)
			return false ;
		else
			return true;
	} 
	else
		return false ;	
}

bool is_ok(int j,int i)			//判断在j状态下最后一次刷的是i区域是否合法(这里是可以优化的,可以通过预处理优化); 
{
	for(int k=1;k<=N;k++)
	{
		if(k==i)	continue ;	
		if(up(k,i))
		{
			if(0 == (j&(1<<(k-1))))
				return false ;	
		}
	}	
	return true;
}

int DP()
{
	int new_s ;
	for(int i=1;i<=N;i++)
	{
		for(int j=0;j<(1<<N);j++)
		{
			dp[i][j] = 20 ;	
		}	
	}
	for(int j=0;j<(1<<N);j++)
	{
		for(int i=1;i<=N;i++)
		{
			new_s = (j&(1<<(i-1)));
			if(new_s==0 || !is_ok(j,i))	continue ;			//考虑当前墙i是最后刷的是否合法 
			new_s = ( j^(new_s) ) ;
			if(new_s == 0)
			{
				dp[i][j] = 1;			//相当于初始化 
				continue ;	
			}
			int min_ = 20 ;
			for(int k=1;k<=N;k++)		//寻找前一状态 
			{
				if(!is_ok(new_s,k)) continue ;
				if(block[k].color == block[i].color)
				{
					min_ = min(min_,dp[k][new_s]);	
				}	
				else	
					min_ = min(min_,dp[k][new_s]+1) ;
			}
			dp[i][j] = min_ ;		
		}	
	}
	int min_ = 20 ;
	for(int i=1;i<=N;i++)
	{
		min_ = min(min_ ,dp[i][(1<<N)-1]) ;
	}	
	return min_ ;
}


int main()
{
	int T;
    //freopen("1in.txt","r",stdin);
    //freopen("1out.txt","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&N);
		for(int i=1;i<=N;i++)
		{
			scanf("%d %d %d %d %d",&block[i].uly,&block[i].ulx,&block[i].lry,&block[i].lrx,&block[i].color);
		}	
		sort(block+1,block+N+1);
		int ans = DP();
		printf("%d\n",ans);
	}
    return 0;
}



你可能感兴趣的:(ZOJ_Painting A Board 状态DP)