zoukankan      html  css  js  c++  java
  • luogu P1283 【平板涂色】

    闲话

    第一道完全靠自己想出的蓝题,怎么说也要写篇题解纪念一下

    思路

    看完题面,使用DFS应该是很显然了

    但是不同于普通深搜的枚举,这道题有一个限制条件

    那就是一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色

    所以我在开始搜索前做了预处理,处理出了每个矩形在涂色前有哪些矩形需要先涂好,搜索时再去判断

    每个需要预涂的矩形是否已先涂好

    另外,由于搜索时我是一次性将所有可以涂色的涂完,所以需要先对所有矩形按照从上到下的顺序进行排序,这样就可以保证在一次性的涂色中,当我要涂下方的矩形时,上方的同颜色矩形已经涂完了

    之后的事情就非常简单,只要照着DFS的模板打就行了

    没有剪枝好像由于数据范围过小水过了

    AC代码如下(带很详细的注释)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n,minn=1e9,tot,sum[17],ss[17][17],ans[1000],v;sum[i]代表第i个矩形上方紧靠着的矩形数
    struct node{              //ss[i][j]代表第i个矩形的第j个紧靠着的矩形是哪一个 
    	int x1,y1,x2,y2;
    	int d;
    }s[17];//s[i].x1和y1代表第i个矩形左上方点的坐标,s[i].x2和y2代表右下方点的坐标,s[i].d代表要涂的颜色 
    bool ex[17];
    void dfs(int k,int su)//k为拿起刷子的次数,su为已经涂色的矩形数目 
    {
    	if(su==n)
    	{
    		minn=min(minn,k);
    		return;
    	}
    	for(int g=1;g<=tot;g++)//tot为颜色总数
    	{
    		int f=su,lin[17],ff=0;//lin[i]为临时数组,用来记录新涂了哪些矩形,方便之后回溯 
    		for(int i=1;i<=16;i++)lin[i]=0; 
    		for(int i=1;i<=n;i++)
    		{
    			if(s[i].d==g&&ex[i]==0)
    			{
    				int si=0;
    				for(int j=1;j<=sum[i];j++)//判断需要的矩形有几个已经预先涂好 
    				if(ex[ss[i][j]])si++;
    				if(si==sum[i])//如果都涂好了就说明可以涂这个矩形了 
    				{
    					ex[i]=1;lin[++ff]=i;//标记为已涂过 
    					su++;
    				}
    			}
    		}
    		if(f==su)continue;//如果用这个颜色不能涂更多矩形,就换一个颜色 
    		ans[++v]=g;//记录每一次使用的颜色 
    		if(ans[v-1]!=ans[v]&&v!=1)//如果与上一次使用的颜色不同,就将次数加1 
    		dfs(k+1,su);
    		if(ans[v-1]==ans[v]||v==1)//如果与上一次使用的颜色相同或者是第一次使用,就不加次数 
    		dfs(k,su);
    		ans[v]=0;--v;//回溯 
    		for(int i=1;i<=ff;i++)
    		ex[lin[i]]=0,su--;
    	}
    }
    bool cmp(node a,node b)
    {
    	if(a.x1==b.x1)return a.y1<b.y1;
    	return a.x1<b.x1;
    }
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>s[i].x1>>s[i].y1>>s[i].x2>>s[i].y2>>s[i].d;
    		tot=max(tot,s[i].d);//更新tot 
    	}
    	sort(s+1,s+n+1,cmp);//从上到下排序 
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    	{
    		if(i!=j)
    		{    //如果其他矩形的y1与y2有一个在此矩形的y1与y2之间,并且是紧靠着的,就是合法的 
    			if(((s[j].y1>=s[i].y1&&s[j].y1<s[i].y2)||(s[j].y2>s[i].y1&&s[j].y2<=s[i].y2))&&s[j].x1<s[i].x1&&s[i].x1==s[j].x2)
    			{
    				sum[i]++;//个数加1 
    				ss[i][sum[i]]=j;//记录是哪个矩形 
    			}
    		}
    	}
    	dfs(1,0);
    	printf("%d",minn);
    	return 0;
    }
    

    第一次写题解,如有不妥之处还请海涵

  • 相关阅读:
    测试工作效率低思考和改进
    Linux环境变量配置方法
    Linux上error while loading shared libraries问题解决方法
    PyCharm工具配置和快捷键使用
    Linux chattr和lsattr命令使用方法
    PuTTY工具配置和使用方法
    Python+AutoIt实现界面工具开发
    我对测试工作的一些认识
    Windows终端工具_MobaXterm
    Cygwin工具安装和使用指导书
  • 原文地址:https://www.cnblogs.com/luotao0034/p/14063174.html
Copyright © 2011-2022 走看看