この記事は、『C++アルゴリズムの宮殿に足を踏み入れる「深層検索基礎トレーニング」入門 (1)』および 『C++アルゴリズムの宮殿に足を踏み入れる「深層検索基礎トレーニング」入門 (2)」を再編集したものです。一年前 。
これで老人の思い出が蘇ることを願っています。
シャオハンがアリーナに入ってきた、もうすぐ試合が始まる...
司会者: Deep Search Basic Training のコンテストサイトへようこそ。まず第一に、私たちのために心を込めて穴を掘り、問題を解決するために知恵を絞ってくれた先生たちに感謝します。次に、風変わりな農夫のジョンに感謝します。最後に、C++ に感謝します。くだらない話はやめて、競争が始まります。
シャオハンは最初の質問を見た...
【探索・後戻りアルゴリズム】Nクイーンズ問題
シャオハンは見る(タイトル)
時間制限: 1000 ミリ秒 スペース制限: 262144 KB 特定の制限
タイトル説明:
n(n<=12) 個のクイーンを nXn チェス盤上に配置し、互いに攻撃できないようにします (つまり、2 つのクイーンが同じ行、列、または対角線上に存在することはできません)。あらゆる方法を考えてみてください。
入力:
数値 n を入力してください。(n<=12)
出力:
すべての順列の合計数を出力します。
入力例:
4出力例:
2
シャオハンは考えた(考えた)
1.法定検査
つまり、次のことを判断する必要があります。
1) 同じ列にありますか
2) 左のスラッシュにありますか: (行 + 列) の値は等しくありません (絶対値)
3) 右側のスラッシュ: (列 - 行) の値が等しくない(絶対値)かどうか
4) なぜ各行を判断する必要がないのですか?
DFS では、x はすでに行を表しており、アルゴリズムによれば行は 1 つしかないため、判断する必要がありません。
3. DFS検索
1) 終了条件: 現在の行番号 = クイーンの総数、つまり、最後の行がクイーンに正常に配置されました。
2) 連続して各位置をループします。攻撃イベントが発生しない場合、クイーンをこの位置に配置できます。
3) 次の行の検索を続けます。つまり、渡されたパラメータは現在の行番号 + 1 です。
Xiaohangが書いた(コード)
#include<iostream>
using namespace std;
int a[105],b[105],c[105],n,s;//数组a为判断列是否放置皇后,b、c都是判断对角线是否放置皇后
void dg(int x)//循环行
{
for(int i=1;i<=n;i++)//循环列
{
if(a[i]!=1&&b[x+i]!=1&&c[i-x+n-1]!=1)
{
a[i]=1;
b[i+x]=1;
c[i-x+n-1]=1;//上面两步及这步都是标记
if(x==n)
{
s++;//当放到最后一个,方案数增加
}
else
{
dg(x+1);//进入下一行放置
}
a[i]=0;
b[i+x]=0;
c[i-x+n-1]=0;//回溯
}
}
}
int main()
{
cin>>n;
dg(1);
cout<<s;//输出方案数
}
シャオハンは最初の質問をすぐに終えて、次の質問の準備をしていました...
[検索とバックトラッキングのアルゴリズム] ローディングの問題 (標準 IO)
時間制限: 1000 ミリ秒 スペース制限: 262144 KB 特定の制限
タイトル説明:
積載量 c の船に n 個のコンテナを積み込むバッチがあり、コンテナ i の重量は wi です。船を可能な限り満杯にするための最適な積載計画を見つけます。つまり、積載量が制限されていない場合は、できるだけ重いコンテナを船に積載します。
入力:
最初の行には 2 つの正の整数 n と c があります。n はコンテナの数、c は船の積載量です。次の 1 行には、コンテナの重量を表す n 個の正の整数があります。
出力:
計算された最大積載重量を出力します
入力例:
5 10 7 2 6 5 4出力例:
10データ範囲の制限:
n<=35、c<=1000
「実際、これは非常に単純なナップザック問題であり、再帰で解決できます。」 Xiaohang は考えました、「一時的な重みと最終的な重みを作成し、検索結果が最終結果よりも大きい場合は、値を代入するだけです。」
#include<iostream>
using namespace std;
int n,c,w[40],s;
void dfs(int x,int sx)//第x个物品,sx为临时重量
{
if(x>n)
{
if(sx>s) s=sx;//赋值
return;
}
else
{
if(sx+w[x]<=c)//如果装入此物品,还没超载的话……
{
dfs(x+1,sx+w[x]);//装入此物品,并搜索下一件物品
}
dfs(x+1,sx);//在不装入此物品的情况下,搜索下一件物品
}
}
int main()
{
cin>>n>>c;
for(int i=1;i<=n;i++) cin>>w[i];
dfs(1,0);
cout<<s;//输出最终重量
}
しかし。Xiaohang さんは後になって、この一見単純なプログラムがタイムアウト寸前であることに気づきました。折り合いがつかず、彼は次のように修正しました。
#include<bits/stdc++.h>
using namespace std;
int n,c,w[40],s,b[40],ms=0;
void dg(int x)
{
if(s>=c)
{
if(s==c)
{
printf("%d",s);
exit(0);
}
s-=w[x-1];
if(ms<s)
ms=s;
s+=w[x-1];
}
else if(x==n)
{
if(ms<s)
ms=s;
}
else
{
s+=w[x];
dg(x+1);
s-=w[x];
dg(x+1);
}
return;
}
int main()
{
scanf("%d%d",&n,&c);
for(int i=0;i<n;i++)
scanf("%d",&w[i]);
dg(0);
printf("%d",ms);
return 0;
}
#include<bits/stdc++.h>
名前空間 std を使用します。
int n,c,w[40],s,b[40],ms=0;
void dg(int x)
{ if(s>=c) { if(s==c) { printf("%d",s); 終了(0); s- =w[x-1]; if(ms<s) ms=s; s+=w[x-1]; if(x==n) { if(ms<s) ms=s; } } else { s+=w[x]; dg(x+1); s-=w[x]; dg(x+1); } 戻り値; }
int main()
{ scanf("%d%d",&n,&c); for(int i=0;i<n;i++) scanf("%d",&w[i]); dg(0); printf("%d",ms); 0を返します。}
これにより実行時間が大幅に短縮されます。
そうこうしているうちに、次の疑問が浮かび上がってきました…。