HDU 4620 Fruit Ninja Extreme(2013多校第二场 剪枝搜索)

时间:2022-06-01 08:41:15

这题官方结题报告一直在强调不难,只要注意剪枝就行。

这题剪枝就是生命....没有最优化剪枝就跪了:如果当前连续切割数加上剩余的所有切割数没有现存的最优解多的话,不需要继续搜索了

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
# define MAX 33
using namespace std; struct node {
int id,tim,total;
int fr[11];
}cuts[MAX];
int n,m,w;
int ans[MAX],final,tmp[MAX],vis[222];
bool cmp (node a,node b) {
return a.tim < b.tim;
} void dfs(int v0,int step,int cur,int num) { // 源点,切割数,当前切割时间,已经切过的水果数
if(step > final) {
final = step;
for (int i=0; i<step; i++) ans[i] = tmp[i];
}
if(step + n - v0 - 1 <= final) return; //最优化剪枝
if(m - num < 3) return ;
int cnt = 0;
for(int i=v0+1; i<n; i++) {
if(cur == 0 || cuts[i].tim - cur <= w) { //cur为零时每个点作为第一刀都有可能
cnt = 0;
int erase[15]; //之前设为全局变量....各种跪
for(int j=0; j<cuts[i].total; j++) {
if(vis[cuts[i].fr[j]] == 0) {
cnt ++;
erase[cnt] = cuts[i].fr[j];
vis[cuts[i].fr[j]] = 1;
}
}
if(cnt >= 3) {
tmp[step] = cuts[i].id;
dfs(i,step+1,cuts[i].tim,num + cnt);
}
for(int j=1; j<=cnt; j++) vis[erase[j]] = 0;
}
}
} int main() {
int T;
cin >> T;
while(T--) {
scanf("%d%d%d",&n,&m,&w);
for(int i=0; i<n; i++) {
scanf("%d%d",&cuts[i].total,&cuts[i].tim);
cuts[i].id = i+1;
for(int j=0; j<cuts[i].total; j++) {
scanf("%d",&cuts[i].fr[j]);
}
}
final = 0;
memset(vis,0,sizeof(vis));
sort(cuts,cuts+n,cmp);
dfs(-1,0,0,0);
printf("%d\n",final);
sort(ans,ans+final);
for(int i=0; i<final; i++) {
if(i != final -1)
printf("%d ",ans[i]);
else printf("%d\n",ans[final - 1]);
}
}
return 0;
}