EOJ 2860 DLX

 

大概就是选最少的人能打败所有人

然后把每个人能打败的人作为行,一共的人作为列重复覆盖

注意:自己是能打败自己的

DLX用起来挺简单的:

1.insert 插入行列,表示能覆盖

2.solve 二分找答案(感觉应该从小到大写 IDA*)

 

#include <cstdio>
#include <deque>
#include <set>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;

#define Debug(x) (cerr << #x << " = " << (x) << endl)
#define Debug2(x, y) (cerr << #x << " = " << (x) << ", " << #y << " = " << (y) << endl)
template<class T> inline T& RD(T &x){  
    char c; for (c = getchar(); c < '0'; c = getchar()); x = c - '0'; for (c = getchar(); '0' <= c && c <= '9'; c = getchar()) x = x * 10 + c - '0';  
    return x;  
}


const int inf = 0x3f3f3f3f;


const int N = 256*256;
const int MAXN = 256;
const int MAXM = 256;

int L[N],R[N],U[N],D[N],nc[N],nr[N];

int col[MAXN],row[MAXM],sz[MAXN];
int head,eid,cn;
//id  chazai h youmian
void linkLR(int &h, int &id){
	L[R[h]] = id;
	L[id] = h;
	R[id] = R[h];
	R[h] = id;
}
//id chazai h xiamian
void linkUD(int &h,int &id){
	U[D[h]] = id;
	U[id] = h;
	D[id] = D[h];
	D[h] = id;
}

void init(){
	memset(nc,-1,sizeof(nc));
	memset(col,-1,sizeof(col));
	memset(row,-1,sizeof(row));
	eid = 1,cn = 0;
	L[head] = R[head] = U[head] = D[head] = head = 0;	
}

void inr(int r){
	linkUD(head,eid);
	L[eid] = R[eid] = eid;
	row[r] = eid ++;
}

void inc(int c){
	linkLR(head,eid);
	U[eid] = D[eid] = eid;
	nc[eid] = c;
	sz[c] = 0;
	++ cn;
	col[c] = eid ++;
}

void inm(int r,int c){
	int rid = row[r],cid = col[c];
	linkLR(rid,eid);
	linkUD(cid,eid);
	nc[eid++] = c;
	++sz[c];
}

void insert(int r,int c){
	if(col[c] == -1)inc(c);
	if(row[r] == -1)inr(r);
	inm(r,c);
}


void remove(int c){
	int i,j;
	for(i=D[c];i!=c;i=D[i]){
		L[R[i]] = L[i];
		R[L[i]] = R[i];
		sz[nc[i]]--;
	}
}


void resume(int c){
	int i,j;
	for(i=U[c];i!=c;i=U[i]){
		L[R[i]] = i;
		R[L[i]] = i;
		sz[nc[i]] ++;
	}
}

int cq(){
	bool hash[MAXN];
	int c,i,j,ret=0;
	memset(hash,0,sizeof(hash));
	for(c=R[head];c!=head;c=R[c]){
		if(!hash[nc[c]]){
			ret ++;
			hash[nc[c]] = true;
			for(i=D[c];i!=c;i=D[i]){
				for(j=R[i];j!=i;j=R[j]){
					if(nc[j] != -1){
						hash[nc[j]] = true;
					}
				}
			}
		}
	}
	return ret;
}

//lim weisuoyaoqiude zuiyoujie
bool dfs(int d,int lim){

	if(d+cq()>lim)return false;
	if(R[head] == head)return true;
	int i,j,c,maxx=1<<28;
	for(i=R[head];i!=head;i=R[i]){
		if(sz[nc[D[i]]] < maxx){
			maxx = sz[nc[D[i]]];
			c = i;
		}
	}
	int key = 0;
	for(i=D[c];i!=c;i=D[i]){
		remove(i);
		for(j=R[i];j!=i;j=R[j]){
			if(nc[j]!=-1)remove(j);
		}
		if(dfs(d+1,lim))key = 1;
		for(j=L[i];j!=i;j=L[j]){
			if(nc[j]!=-1)resume(j);
		}
		resume(i);
		if(key)break;
	}
	if(key)return true;
	return false;
}


int solve(int n){
	int l = 0,r = n,m,ans;
	while(l <= r){
		m = (l+r) >> 1;

		if(dfs(0,m)){
			ans = m;
			r = m - 1;
		}
		else {
			l = m + 1;
		}
	}
	return ans;
}


map<string,int> name;
string s;

void init_name(int n){
	name.clear();
	for(int i=0;i<n;i++){
		cin >> s;		
		name[s] = i;
	} 
}



int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		init_name(n);
		init();
		for(int i=0;i<n;i++){
			insert(i,i);
		}
		for(int i=0;i<m;i++){
			cin >> s;
			int id = name[s];
			int t;
			//insert(id,id);
			scanf("%d",&t);
			while(t --){
				cin >> s;
				int idd = name[s];
				insert(id,idd);
			}		
		}
		int ans = solve(n);
		printf("%d\n", ans);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值