問題
序文
私は実際には2つのBBを考えます,,,このトピックスーパーシンプルですが、間違ったトピック×2リードは私の一日の気分に影響を与えることがあるため。。。
もちろん、私はこの問題に良い解決策をしたい、とあなたはそれを持って気分がqwq!
解決
最初の注:問題のこのバスラインは厳密である(\ 0-59)\などの範囲内で等差数列、(3,6,9,12- \)は\違法バス路線であり、\(3 、6,9、...、57 \)は、有効なバス路線であります
完全に主題を理解した後、我々はすぐに問題解決のアイデアを期待することができます----
- \(1 \)前処理は、すべての法的バス路線うち、各ルートはバス等差数列である、タプル\((X、d)は\ ) 、を示すために(X \)\、最初に\(dは\)を示す、寛容であるバスの到着時間分布の経路\(X + D、X- + 2D、...、X- + KDが\)(\ (K \)満たされる\(X + KD <60 \) )、これらの瞬間最大の負でない整数です。
前処理があり、詳細は:注意\(3,6,9、...、57 \)と\(6,9、...、57 \)も、正当なバス路線ではありません。私たちは、このような状況の列挙を避けたい、それがあることを保証する必要がある\(xDで<0 => D> X- \) (というこの性を保証\(XDは\)ではありません\(0-59 \) 、劣らず開始点)
\(2 \) DFSは、我々はすべての時間を埋めるためだけの積み重ね列挙することができコンビナトリアル+ IDFS、バス路線を達成。
\(3 \)の最適化を剪定:
1。 好き 列挙順序の最適化:我々は、我々が降順にすべてのポイントのバスルートに影響を与えることができ、より多くのいくつかの点で影響を与え、各列挙バス路線の時にできるだけたい
2.追加の剪定(便利):私たちは列挙することができた場合は(K \)\バス路線ですが、また、我々は降順のバス路線を持っているので、私たちは、から現在の仮定(\今は)\列挙を開始します\ (今\)このバス路線が持つ\(M \)点を、電流は影響を受けた\(S \)ポイントの合計\(N- \)場合、ポイントを\(S + K * M < N \) 、その後、直接return
(ほとんどはも影響を与える可能性があるため、\(K * M \)ポイントが十分ではなかったものをすべて足し、この分岐は成功しません)
私は<%_>スパート%後qwq、コンビナトリアルの元々のDFSの複雑さに加え、剪定の時の複雑さを分析しません。
コード
トークではcheap.Show私のコードです。
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
const int N = 67, MAXN = 3607;
int n,cnt,idt;
int bus[N];
struct Node {
int x,d,nums;
bool operator < (const Node &el) const {
return nums > el.nums; //经典剪枝:优化搜索顺序,从大到小搜
}
}route[MAXN]; //route 线路
inline bool check(int x,int d) {
for(int i=x;i<60;i+=d)
if(!bus[i]) return false;
return true;
}
bool Dfs(int dep,int now,int res) {
if(dep == idt) return (res == n);
if(res+(idt-dep)*route[now].nums < n) return false; //在线剪枝
for(int i=now;i<=cnt;++i) {
int x = route[i].x, d = route[i].d, nums = route[i].nums;
if(check(x,d)) {
for(int j=x;j<60;j+=d) bus[j]--;
if(Dfs(dep+1,i,res+nums)) return true;
for(int j=x;j<60;j+=d) bus[j]++;
}
}
return false;
}
int main()
{
n = read();
for(int i=1,pos;i<=n;++i) {
pos = read(); ++bus[pos];
}
for(int i=0;i<60;++i)
for(int j=i+1;i+j<60;++j)
if(check(i,j)) route[++cnt] = (Node)<%i,j,(59-i)/j+1%>;
//printf("test cnt = %d\n",cnt);
sort(route+1, route+1+cnt);
idt = 0;
while(!Dfs(0,1,0)) {
++idt;
if(idt > 17) {
puts("Unkown Problems!");
return 0;
}
}
printf("%d\n",idt);
return 0;
}
概要
慎重にタイトル、慎重に分析、真剣に考えを見て!!!
組み合わせ列挙モデル取得
等差数列を取得
最適化検索に大法順序を取得します。