hdu 1455 dfs検索の湊棒
原題アドレス
この問題はpojの少林神棍を救うのと同じ問題だ.
与えられた棒で等長の棒を寄せ集め、寄せられる棒の最小長さを求める.
直感的なバッグの中の考え方は、すべての可能な長さを列挙し、それから棒の組み合わせをテストし続け、まず棒を組み合わせに加え、それから適切でない場合はこの棒を倒し、次の棒をテストして、すべての棒を倒すまでテストします.
列挙する時、私たちは最も長い棒の長さから、棒の総長の半分まで列挙すればいいだけです.そしてこれ以上合わないと、すべての棒が1本の棒にしかならないことを意味します.
私はpojで少林神棍を救うというテーマについて詳しく説明したことがある.DFS検索問題です.ここでDFSには4つの枝切りスキームがあります.
最初は4種類の枝を切りました.しかし、まだタイムアウトで、何も言わなかった.
最後にDFS以外のmain関数に剪定があることを発見しました.私は使っていません.テストする長さは必ず全長の因数でなければ、この長さをテストする必要はありません.棒は同じ長さなので、1本1本の長さはもちろん全長の因数です.この枝が書いていないのでタイムアウトしました.
#include<iostream>
#include<cstring>
#include<functional>
#include<algorithm>
using namespace std;
bool used[64];
int len[64],n,l,last;
bool dfs(int r,int m)
{
if(r==0&&m==0)
return true;
if(m==0)
m=l;
int start=0;
if(m!=l)
start=last+1;
for(int i=0;i<n;i++)
{
if(!used[i]&&len[i]<=m)
{
if(i>0)
{
if(used[i-1]==false&&len[i]==len[i-1])
continue;
}
used[i]=true;
last=i;
if(dfs(r-1,m-len[i]))
return true;
else
{
used[i]=false;
if(len[i]==m||m==l)
return false;
}
}
}
return false;
}
int main()
{
while(cin>>n)
{
if(!n)
break;
int total=0;
for(int i=0;i<n;i++)
{
cin>>len[i];
total+=len[i];
}
sort(len,len+n,greater<int>());
for(l=len[0];l<=total/2;l++)
{
if(total%l)// 。。
continue;
memset(used,false,sizeof(used));
if(dfs(n,l))
{
cout<<l<<endl;
break;
}
}
if(l>total/2)
cout<<total<<endl;
}
return 0;
}