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可行性剪枝,如果当前选择的高手的数量已经大于等于当前最优解的数量,剪。这也是最基础,最简单,但却是最实用的剪枝之一。
这种情况下,这个高手就不需要了,因为它完全可以被另外那个高手取代0.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;
}