完成工作

Description

当前有n(n<=12)个工作,和8个工人。现在每个工作需要占用一个工人的从[a,b]这个区间的时间(一个工人自然不可能在同一个时间做2个不同的工作),且一个工作不一定是所有工人都能够完成的。现在给出每个工作的描述,问是否存在一种安排方案使得所有工作都能完成。

Input

有多组数据。第一行一个数tot表示数据的组数,后面紧接tot组数据。
对于每一组数据的第一行有一个整数n,表示工作的数目。后面n行每行描述一个工作。
对于一个工作,a,b,k,h1,h2……hk来描述,表示这个工作需要占用一个工人[a,b]的时间,并且能够完成这个工作的工人只有k个,标号分别是h1,h2……hk。

Output

对于每组输入数据,输出一行YES(如果可以安排一种方案使得工作完成)或者是NO(无法安排一种方案)

Sample Input

2

2

1 1 1 1

2 2 1 1

2

1 2 1 1

2 2 1 1

Sample Output

YES

NO

首先这是一道可行性判定问题。

我们注意到工作完成先后顺序是没有影响的,而且影响范围是一个区间,因此想到了拆分思想,也就是说将一个工作拆成开始和完成两个区间(对于只有两种状态的集合元素,这是一个套路),用工人作为状态进行递推。

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int tot= (1<<8)-1;//工人状态总数 
struct Work{int f,ti,id;}a[27];
int f[27][tot];//表示第i个工作开始(结束)时,工人做工情况 
int n,nd[13][9];
bool cmp(const Work&A,const Work&b){
	return (A.ti<b.ti)||(A.ti==b.ti&&A.f>b.f);
}
void init(){//拆分 
	memset(f,0,sizeof(f));
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&a[i*2-1].ti,&a[i*2].ti,&nd[i][0]);
		a[i*2-1].f=1;a[i*2].f=0;
		a[i*2-1].id=a[i*2].id=i;
		for(int j=1;j<=nd[i][0];j++)scanf("%d",&nd[i][j]),--nd[i][j];
	}
	sort(a+1,a+1+n*2,cmp);
}
inline void dp(){
	f[0][0]=1;
	Inc(i,0,n*2-1)
		Inc(j,0,tot)
			Inc(k,1,nd[a[i+1].id][0])
				if(a[i+1].f){//工作开始
					if(!(j&(1<<nd[a[i+1].id][k])))continue;//工作开始时工人k不在
					f[i+1][j]|=f[i][j^(1<<nd[a[i+1].id][k])];
				}else {
					if((j&(1<<nd[a[i+1].id][k])))continue;//工作结束时工人k还在做
					f[i+1][j]|=f[i][j|(1<<nd[a[i+1].id][k])]; 
				}
	if(f[2*n][0])puts("YES");
	else puts("NO");
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		init();
		dp();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dancingz/article/details/81151859