预处理dfs

 Shut the Box

Time Limit: 5 Sec   Memory Limit: 128 MB
Submit: 9   Solved: 5
[ Submit][ Status][ Web Board]

Description

Shut the Box is a one-player game that begins with a set of N pieces labeled from 1 to N. All pieces are initially "unmarked" (in the picture above, the unmarked pieces are those in an upward position). In the version we consider, a player is allowed up to T turns, with each turn defined by an independently chosen value V (typically determined by rolling one or more dice). During a turn, the player must designate a set of currently unmarked pieces whose numeric labels add precisely to V, and mark them. The game continues either until the player runs out of turns, or until a single turn when it becomes impossible to find a set of unmarked pieces summing to the designated value V (in which case it and all further turns are forfeited). The goal is to mark as many pieces as possible; marking all pieces is known as "shutting the box." Your goal is to determine the maximum number of pieces that can be marked by a fixed sequence of turns.

 

As an example, consider a game with 6 pieces and the following sequence of turns: 10, 3, 4, 2. The best outcome for that sequence is to mark a total of four pieces. This can be achieved by using the value 10 to mark the pieces 1+4+5, and then using the value of 3 to mark piece 3. At that point, the game would end as there is no way to precisely use the turn with value 4 (the final turn of value 2 must be forfeited as well). An alternate strategy for achieving the same number of marked pieces would be to use the value 10 to mark four pieces 1+2+3+4, with the game ending on the turn with value 3. But there does not exist any way to mark five or more pieces with that sequence.

Hint: avoid enormous arrays or lists, if possible.

Input

Each game begins with a line containing two integers, NT where 1 ≤ N ≤ 22 represents the number of pieces, and 1 ≤ T ≤ N represents the maximum number of turns that will be allowed. The following line contains T integers designating the sequence of turn values for the game; each such value V will satisify 1 ≤ V ≤ 22. You must read that entire sequence from the input, even though a particular game might end on an unsuccessful turn prior to the end of the sequence. The data set ends with a line containing 0 0.

Output

You should output a single line for each game, as shown below, reporting the ordinal for the game and the maximum number of pieces that can be marked during that game.

Sample Input

6 4 
10 3 4 2
6 5
10 2 4 5 3
10 10
1 1 3 4 5 6 7 8 9 10
22 22
22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0

Sample Output

Game 1: 4
Game 2: 6
Game 3: 1
Game 4: 22
先DFS预处理出1-22这些数可以覆盖的块,后面就是直接搜索就行了。
我竟然sb的用深搜+回溯,结果果断不出结果了,而且还wa。搜索好题
View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;
vector<int> v[25];

void dfs(int x,int pos,int n,int state)
{
if(!x)
{
v[n].push_back(state);
return;
}
if(x>pos*(pos+1)/2) return;
for(int i=min(pos,x);i>=1;i--)
dfs(x-i,i-1,n,state|(1<<(i-1)));
}
int c[1<<22];
set<int> s1,s2; //s1 s2像一个接力棒一样
void bit_cal(int n)
{
for(int i=0;i<22;i++)
if(n&(1<<i)) c[n]++;
}
void init()
{
memset(c,0,sizeof(c));
for(int i=0;i<(1<<22);i++)
bit_cal(i);
for(int i=1;i<=22;i++)
{
v[i].clear();
dfs(i,i,i,0);
sort(v[i].begin(),v[i].end());
// printf("%d %d\n",i,v[i].size());
}
}
int main()
{
init();
// cout<<c[(1<<21)-1]<<endl;
int n,m,Tcase=0;
int t[25];
while(scanf("%d %d",&n,&m)==2)
{
if(!n&&!m) break;
for(int i=1;i<=m;i++)
scanf("%d",&t[i]);
s1.clear();
s1.insert(0);
set<int>::iterator it;
int ans=0;
for(int i=1;i<=m;i++)
{
int maxn=0,state;
for(it=s1.begin();it!=s1.end();it++)
{
// cout<<v[t[i]].size()<<endl;
for(int k=0;k<v[t[i]].size();k++)
{
if(v[t[i]][k]>=(1<<n)) break;
if((*it)&(v[t[i]][k])) continue;
state=(*it)|v[t[i]][k];
//cout<<state<<endl;
s2.insert(state);
maxn=max(maxn,c[state]);
}
}
// cout<<maxn<<endl;
if(!maxn) break;
ans=max(ans,maxn);
if(ans==n) break;
s1.clear();
for(it=s2.begin();it!=s2.end();it++)
s1.insert(*it);
s2.clear();
}
printf("Game %d: %d\n",++Tcase,ans);
}
return 0;
}
贴下我的tle+wa的代码,警告= =
View Code
#include <iostream>
#include <cstdio>

using namespace std;
int turn[30],n,m,ans;
int mark[30];

void dfs(int id,int rest,int num)
{
if(num>ans) ans=num;
if(ans==n) return;
if(id>=m) return;
if(id==m-1&&rest==0) return;
if(rest==0)
{
dfs(id+1,turn[id+1],num);
return;
}
for(int i=1;i<=n&&rest>=i;i++)
if(!mark[i])
{
mark[i]=1;
dfs(id,rest-i,num+1);
mark[i]=0;
}
}
int main()
{
int i,j;
while(scanf("%d %d",&n,&m)==2)
{
for(i=0;i<m;i++)
scanf("%d",&turn[i]);
ans=0;
memset(mark,0,sizeof(mark));
dfs(0,turn[0],0);
printf("%d\n",ans);
}
return 0;
}

转载于:https://www.cnblogs.com/one--world--one--dream/archive/2012/03/24/2415646.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值