HUST - 1017 精确覆盖

题目:给你N*M的01矩阵,让你选择最少的行,使得每一列都恰好包含一个1

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template T f_abs(T a){ return a > 0 ? a : -a; }
template T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
// 0x3f3f3f3f

int limit;//重复覆盖时使用,行数选择的最大数目
struct DLX {
	const static int ROW = 1003, COL = 1003, SIZE = ROW * COL;
	int L[SIZE], R[SIZE], U[SIZE], D[SIZE];  //模拟指针
	int col[SIZE], row[SIZE]; //所在列 所在行
	int visn, visited[COL]; //用于估价函数
	int sel[ROW], seln; //选择的行
	int sz[COL]; //列元素数
	int total/*节点编号*/, H[ROW];
	void init(int clen) { //初始化列头指针
		for(int i = 0; i <= clen; ++i) {
			L[i] = i - 1; R[i] = i + 1;
			U[i] = D[i] = i; sz[i] = 0;
		}
		for(int i=0;i sz[i]) c = i;
		remove(c);
		for(i = D[c]; i != c; i = D[i]) { //删除与c相连的行i
			for(j = R[i]; j != i; j = R[j]) //删除行元素所在的列j
				remove(col[j]);
			sel[now] = row[i]; //选择此行 保存行号
			if(dance(now + 1)) { //对于不同的题 这个地方常常需要改动
				return true;
			}
			for(j = L[i]; j != i; j = L[j])
				resume(col[j]);
		}
		resume(c);
		return false;
	}
//-------------------- 重复覆盖 -------------------------
	void _remove(const int &c) {
		for(int i = D[c]; i != c; i = D[i])
			L[R[i]] = L[i], R[L[i]] = R[i];
	}
	void _resume(const int &c) {
		for(int i = U[c]; i != c; i = U[i])
			L[R[i]] = R[L[i]] = i;
	}
	int Astar(){ //估价函数
		int res = 0; ++visn;
		for(int i = R[0]; i != 0; i = R[i]) {
			if(visited[i] != visn) {
				++res; visited[i] = visn;
				for(int j = D[i]; j != i; j = D[j])
					for(int k = R[j]; k != j; k = R[k])
						visited[col[k]] = visn;
			}
		} return res;
	}
	bool _dance(int now) {
	    if(now + Astar() > limit) return false;
		if(R[0] == 0) return now<=limit;
		int c=R[0], i, j;
		for(i = R[0]; i != 0; i = R[i]) //选择元素最少的列c
			if(sz[c] > sz[i]) c = i;
		for(i = D[c]; i != c; i = D[i]) {
			_remove(i);
			for(j = R[i]; j != i; j = R[j])
				_remove(j);
			if(_dance(now + 1)) { //对于不同的题 这个地方常常需要改动
				return true;
			}
			for(j = L[i]; j != i; j = L[j])
				_resume(j);
			_resume(i);
		}
		return false;
	}
}dl;
int main(){

    int N,M,num;
    while(~scanf("%d%d",&N,&M)){
        dl.init(M);
        for(int i=1;i<=N;i++){
            scanf("%d",&num);
            int j;
            while(num--){
                scanf("%d",&j);
                dl.link(i,j);
            }
        }
        if(!dl.dance(0)) printf("NO\n");
        else{
            printf("%d",dl.seln);
            for(int i=0;i


你可能感兴趣的:(Dancing,Links)