zoukankan      html  css  js  c++  java
  • 【洛谷P4929】【模板】舞蹈链(DLX)

    题目

    题目链接:https://www.luogu.com.cn/problem/P4929
    给定一个(N)(M)列的矩阵,矩阵中每个元素要么是1,要么是0
    你需要在矩阵中挑选出若干行,使得对于矩阵的每一列(j),在你挑选的这些行中,有且仅有一行的第(j)个元素为(1)
    (N,Mleq 500),数字 (1) 的数量 (leq 5000)

    思路

    DLX 可以解决的是精确覆盖问题。也就是任意一个位置被恰好覆盖一次。
    进行操作后为了方便删除未被选择的无用操作,DLX 采用交叉十字循环双向链,使得单次删除和重新插入的复杂度均为 (O(1))
    详解可以见 Blog

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=300010;
    int n,m;
    stack<int> st;
    
    struct DLX
    {
    	int tot,l[N],r[N],u[N],d[N],x[N],y[N],h[N],cnt[N];
    	
    	void build(int m)
    	{
    		memset(h,-1,sizeof(h));
    		for (int i=0;i<=m;i++)
    			l[i]=i-1,r[i]=i+1,u[i]=d[i]=i;
    		l[0]=m; r[m]=0; tot=m;
    	}
    	
    	void ins(int i,int j)
    	{
    		int p=++tot;
    		x[p]=i; y[p]=j; cnt[j]++;
    		u[p]=u[j]; d[u[j]]=p; d[p]=j; u[j]=p;
    		if (h[i]==-1)
    			h[i]=p,l[p]=r[p]=p;
    		else
    			l[p]=l[h[i]],r[l[p]]=p,r[p]=h[i],l[h[i]]=p;
    	}
    	
    	void remove(int k)
    	{
    		r[l[k]]=r[k]; l[r[k]]=l[k];
    		for (int i=d[k];i!=k;i=d[i])
    			for (int j=l[i];j!=i;j=l[j])
    				d[u[j]]=d[j],u[d[j]]=u[j],cnt[y[j]]--;
    	}
    	
    	void resume(int k)
    	{
    		for (int i=u[k];i!=k;i=u[i])
    			for (int j=r[i];j!=i;j=r[j])
    				d[u[j]]=j,u[d[j]]=j,cnt[y[j]]++;
    		r[l[k]]=k; l[r[k]]=k;
    	}
    	
    	bool dance()
    	{
    		if (!r[0])
    		{
    			for (;st.size();st.pop())
    				printf("%d ",st.top());
    			return 1;
    		}
    		int p=0;
    		for (int i=r[0];i;i=r[i])
    			if (cnt[i]<cnt[p] || !p) p=i;
    		if (!p) return 0;
    		remove(p);
    		for (int i=d[p];i!=p;i=d[i])
    		{
    			st.push(x[i]);
    			for (int j=l[i];j!=i;j=l[j]) remove(y[j]);
    			if (dance()) return 1;
    			for (int j=r[i];j!=i;j=r[j]) resume(y[j]);
    			st.pop();
    		}
    		resume(p);
    		return 0;
    	}
    }dlx;
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	dlx.build(m);
    	for (int i=1;i<=n;i++)
    		for (int j=1,x;j<=m;j++)
    		{
    			scanf("%d",&x);
    			if (x) dlx.ins(i,j);
    		}
    	if (!dlx.dance()) printf("No Solution!");
    	return 0;
    }
    
  • 相关阅读:
    省选测试42
    省选测试41
    省选测试40
    省选测试39
    python海龟画图生成星星
    Python-列表简介
    Linux系统中设置默认的Java版本
    虚拟机无线网卡桥接失败
    pycharm设置启动图标
    禁用vscode硬件加速
  • 原文地址:https://www.cnblogs.com/stoorz/p/14246850.html
Copyright © 2011-2022 走看看