zoukankan      html  css  js  c++  java
  • 「UVA1603」破坏正方形 Square Destroyer

    • 前言

      一道 DLX 好题(即 Dancing Links X ),适合刚学来练手。

      用 DLX 就比较好想,也不会很难写(((


    • 分析

      首先,如何想到 DLX ?

      一个正方形有 (4) 条边(每条边若干火柴),选择一根火柴就可以破坏掉正方形。但是也可以选择多根。

      要保证每个正方形内部至少有一根火柴被选择,且要求选择火柴数量最少

      再看看重复覆盖问题:

      给定一个 (N)(M) 列的矩阵,矩阵中每个元素要么是 (1) ,要么是 (0)

      你需要在矩阵中选择若干行,使每一列都至少包含一个 (1) ,并且要求选择的行数最少。

      很明显,这是一道重复覆盖问题。

      接下来就是如何构建了。

      首先,把这些火柴抽象成 (2n(n+1)) 个点。

      然后每根火柴和所在边长为 (len (1 le len le n)) 的矩形的边上所有火柴连起来。

      如下图:(举例点 (1)


    • 代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<vector> 
    #include<algorithm>
    using namespace std;
    const int Maxn=3600+5;
    int T,n,m,l[Maxn],r[Maxn],u[Maxn],d[Maxn],s[Maxn];
    int idx,tot,ans[Maxn],col[Maxn],row[Maxn];
    bool st[Maxn]; // 1.作为估价函数 2.作为建图 
    vector<int> sq[60];
    void init()
    {	for(int i=0;i<=m;i++)
    	{	l[i]=i-1;r[i]=i+1;
    		u[i]=d[i]=col[i]=i;
    		s[i]=0;
    	}
    	l[0]=m;r[m]=0;
    	idx=m+1;
    }
    int h() //估价函数 
    {	int cnt=0;
    	memset(st,0,sizeof(st));
    	for(int i=r[0];i;i=r[i])
    	{	if(st[col[i]])continue;
    		cnt++;
    		st[col[i]]=1;
    		for(int j=d[i];j!=i;j=d[j])
    			for(int k=r[j];k!=j;k=r[k])
    				st[col[k]]=1;
    	}
    	return cnt;
    } 
    void add(int &hd,int &tl,int x,int y)
    {	row[idx]=x;col[idx]=y;s[y]++;
    	u[idx]=y;d[idx]=d[y];u[d[y]]=idx;d[y]=idx;
    	r[hd]=l[tl]=idx;r[idx]=tl;l[idx]=hd;
    	tl=idx++;
    }
    void remove(int p)
    {	for(int i=d[p];i!=p;i=d[i])
    		r[l[i]]=r[i],l[r[i]]=l[i];
    }
    void resum(int p)
    {	for(int i=u[p];i!=p;i=u[i])
    		r[l[i]]=i,l[r[i]]=i;
    }
    bool dfs(int k)
    {	if(k+h()-1>tot)return 0;
    	if(!r[0])return 1;
    	int p=r[0];
    	for(int i=r[0];i;i=r[i])
    		if(s[p]>s[i])p=i;
    	for(int i=d[p];i!=p;i=d[i])
    	{	ans[k]=row[i];
    		remove(i);
    		for(int j=r[i];j!=i;j=r[j])remove(j);
    		if(dfs(k+1))return 1;
    		for(int j=l[i];j!=i;j=l[j])resum(j);
    		resum(i);
    	}
    	return 0;
    }
    int main()
    {	scanf("%d",&T);
    	while(T--)
    	{	int k;
    		scanf("%d%d",&n,&k);
    		m=idx=0;
    		memset(st,0,sizeof(st));
    		memset(col,0,sizeof(col));
    		for(int i=1;i<=k;i++)
    		{	int x;
    			scanf("%d",&x);
    			st[x]=1;
    		}
    		for(int len=1;len<=n;len++)
    			for(int x=1;x+len-1<=n;x++)
    				for(int y=1;y+len-1<=n;y++)
    				{	m++;
    					sq[m].clear();
    					int dd=n*2+1;//一行过去(横n加上竖n+1)个数
    					for(int i=0;i<len;i++) //向一个矩形的 4 边(上下左右)连去 
    					{	sq[m].push_back((x-1)*dd+y+i); //上 
    						sq[m].push_back((x-1)*dd+y+i+dd*len); //下 
    						sq[m].push_back((x-1)*dd+y+n+i*dd); //左 
    						sq[m].push_back((x-1)*dd+y+n+i*dd+len); //右 
    					}
    					for(int i=0;i<sq[m].size();i++) //相连的边有一个断了,直接删除所有即可 
    						if(st[sq[m][i]]){m--;break;}
    				}
    		init();
    		for(int i=1;i<=n*(n+1)*2;i++) //全部边
    			if(!st[i])
    			{	int hh=idx,tl=idx;
    				for(int j=1;j<=m;j++)
    					if(find(sq[j].begin(),sq[j].end(),i)!=sq[j].end()) //连边存在 
    						add(hh,tl,i,j);
    			} 
    		tot=0;
    		while(!dfs(1))tot++;
    		printf("%d
    ",tot);
    	}
    	return 0;
    }
    

    [ ext{by Rainy7} ]

  • 相关阅读:
    ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
    Linux学习安装
    linux中的虚拟环境工具
    linux 文件目录权限
    PHP利用百度ai实现文本和图片审核
    Laravel + Swoole 打造IM简易聊天室
    Mysql索引降维 优化查询 提高效率
    Nginx支持比Apache高并发的原因
    网站高并发解决方案(理论知识)
    mysql大量数据分页查询优化-延迟关联
  • 原文地址:https://www.cnblogs.com/Rainy7/p/14457412.html
Copyright © 2011-2022 走看看