10月20日备战Noip2018模拟赛10(B组) T2 Solve 屠题

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/MOMING_V/article/details/83240966

10月20日备战Noip2018模拟赛10

T2解决了屠题

题目描述

蒟蒻HSQ被布置了Ñ道作业题,可是他一道也不会..但他知道有瓦特个捷克克朗大佬的分身,并知道每只捷克克朗分身会做哪些题(虽然捷克克朗会做所有的题,但是为了题目需要要让他变弱一点),请问HSQ至少请多少位捷克克朗的分身,才能屠完所有的题?

输入格式

第一行两个整数n及W表示有Ñ道作业题和瓦特位捷克克朗的分身,作业题以1..n的编号。接下来瓦特行,第i + 1的行第一个数立表示第我位分身会做的题目的数量,接下来个数表示利第我位捷克克朗分身会做哪些题目。

输出格式

一个数,蒟蒻HSQ至少要请多少位捷克克朗的分身

输入样例


4 4
2 1 2
1 4
3 2 3 4
2 1 3

输出样例

2

数据范围

对于40%的数据,3 <= N,W <= 10,

对于100%的数据,3 <= N,W <= 60,1 <=利<= 6


思路

搜索+剪枝

1可行性剪枝,如果当前选择的高手的数量已经大于等于当前最优解的数量,剪。这也是最基础,最简单,但却是最实用的剪枝之一。

这种情况下,这个高手就不需要了,因为它完全可以被另外那个高手取代.2重复数据数据中不可避免地会出现某一个

3仅有情况有的题只能被一位高手解决,所以在搜索之前把这位高手会做的题目删去吧,最优解中一定包含这位高手,所以这些题一定能被解决。
 

代码

#include <iostream>
#include <cstdio>
 
using namespace std; 
 
const int N = 61; 
const int INF = 0x7fffffff; 
 
int n, m, ans = INF, w; 
int a[N][N], l[N], who[N][N], ok[N], d[N]; 
bool b[N], can[N][N]; 
 
bool be_included(int x)
{
	for (int i = 1; i < x; i ++){
		bool f = 1; 
		for (int j = 1; j <= l[x]; j ++){
		    if (!can[i][a[x][j]]){
		    	f = 0; 
		    	break; 
		    }
		}
		if (f) return true; 
	}
	return false; 
}
 
void dfs(int k, int s)
{
	if (s >= ans) return; 
	if (k > n){
		ans = s; 
		return; 
	}
	if (ok[k] > 0) {
		dfs(k + 1, s); 
		return; 
	}
	
	int use; 
	for (int i = 1; i <= d[k]; i ++){
	    use = who[k][i]; 
		for (int j = 1; j <= l[use]; j ++) ok[a[use][j]]++; 
	    dfs(k + 1, s + 1); 
		for (int j = 1; j <= l[use]; j ++) ok[a[use][j]]--; 
	}
}
 
int main()
{
	//freopen("solve.in", "r", stdin); 
	//freopen("solve.out", "w", stdout); 
	
	scanf("%d %d", & n, & m); 
	for (int i = 1; i <= m; i ++){
		scanf("%d", & l[i]); 
		for (int j = 1; j <= l[i]; j ++){
			scanf("%d", & a[i][j]); 
			can[i][a[i][j]] = true; 
		}
	}
	
	for (int i = 1; i < m; i ++){
		for (int j = i + 1; j <= m; j ++){
	    	if (l[i] < l[j]){
	    		swap(l[i], l[j]); 
	    		for (int k = 1; k <= 6; k ++) swap(a[i][k], a[j][k]); 
	    		for (int k = 1; k <= 60; k ++) swap(can[i][k], can[j][k]); 
	    	}
		}
	}
	
	for (int i = 1; i <= m; i ++){
	    if (!be_included(i)){
	    	w++; 
	    	l[w] = l[i]; 
	    	int tot = 0; 
	    	for (int j = 1; j <= n; j ++){
	    	    if (can[i][j]){
	    			tot++; 
	    			a[w][tot] = j; 
	    			who[j][++d[j]] = w; 
	    		}
	    	}
	    }
	}
	int tot = 0; 
	for (int i = 1; i <= n; ++i){
	  	if (d[i] == 1 && ok[i] == 0){
	    	tot++; 
	    	int use = who[i][1]; 
	    	for (int j = 1; j <= l[use]; ++j)
	    	  ok[a[use][j]]++; 
	    }
	}
	
	dfs(1, tot); 
	
	printf("%d", ans); 
	
	//fclose(stdin); 
	//fclose(stdout); 
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/MOMING_V/article/details/83240966
今日推荐