看到水果忍者一激动,这么长题目一气呵成。。结果后来才知道好多地方理解错了意思。
题意:
首先,一刀切三个或三个以上,连续(两刀之间时间差<=w)这样切,得分最高。
要求算最多可以连续切三个或三个以上多少刀。
给的是:n,m,w 一共多少刀,一共多少水果,两刀时间差的最大值
然后每行 c,t,c1,c2,c3......表示t时刻切了一刀,这一刀切了c个水果,分别编号是c1,c2,c3.....
题目其实是说,给的刀中,可以选择这一刀切还是不切,只要能满足那两个要求的最大值就行了
解法:
先把所有刀按出现的时间排序,
然后开始dfs,记录每一条路咯
要注意的几点:
1、在标记出现过的水果时,很麻烦,如果只用0和1表示是否出现过的话,回溯时不好还原,
那么就把这一刀所有水果的vis++,这样都是非0,后面都不影响,回溯时再--,就可以还原
2、判断是否符合连续&&三个或者三个以上时,还要加上,此时存的长度变量tmpl为0时也符合,表示是第一个,所以可以
3、输出时,按照输入的顺序编号输出
4、要加剪枝啦
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
struct node
{
int t,p[15],c,id;
}cut[35];
bool cmp(node x,node y)
{
return x.t<y.t;
}
int T,longe,ans[35],tmpa[35],tmpl,n,w,m,vis[205],num;
void dfs(int pos,int lastt)
{
if(n-pos+tmpl<=longe) return;//后面每一刀都切 还比最长的短
int num,i,j,tmp;
for(i=pos+1;i<=n;i++)
{
for(j=1,num=0;j<=cut[i].c;j++)//统计没出现过的个数
{
tmp=cut[i].p[j];
if(vis[tmp]==0)
num++;
vis[tmp]++;//便于还原
}
if((cut[i].t-lastt<=w||!tmpl)&&num>=3)
{
tmpl++;
tmpa[tmpl]=cut[i].id;
dfs(i,cut[i].t);
tmpl--;
}
for(j=1;j<=cut[i].c;j++)
{
tmp=cut[i].p[j];
vis[tmp]--;
}
}
if(longe<tmpl)
{
longe=tmpl;
for(j=0;j<longe;j++)
ans[j]=tmpa[j+1];
}
}
int main()
{
int i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&w);
for(i=1;i<=n;i++)
{
scanf("%d%d",&cut[i].c,&cut[i].t);
for(j=1;j<=cut[i].c;j++)
scanf("%d",&cut[i].p[j]);
cut[i].id=i;
}
sort(cut+1,cut+n+1,cmp);
memset(vis,0,sizeof vis);
longe=0;tmpl=0;
dfs(0,cut[1].t);
sort(ans,ans+longe);
printf("%d\n",longe);
for(i=0;i<longe-1;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[longe-1]);
}
return 0;
}