日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pku acm 2248 addtion chians 解题报告

發布時間:2025/3/17 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pku acm 2248 addtion chians 解题报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

acm? 2248
給定n,找最小的序列。
a0 = 1
am = n

a0 < a1 < a2 ... < am

任意 ak = al1 + al2.

l1 l2 可以相等

如 n = 5
找到 1 2 3 5
或者 12 4 5 都可 輸出一個即可

但是 12 3 4 5 就不是最短的了

開始問題沒想好,總是超時,參考了

http://hi.baidu.com/ecjtuzdh/blog/item/ea5d2c025ba7c381d53f7ce9.html

提到問題的關鍵

對于1<=P<=k (a[k]=n) 有a[p]=a[p-1]+a[t] ,t為[0,p-1]中的一個數

剛開始其實也有想到,但是總覺得沒有完全證明,對于a[k]最后一個數這個結論肯定成立,否則序列可更短,但是對于序列中前面的數呢。

1?, 2, 4, 8, 10

1, 2 , 4?, 8 , 16

?問題是 1, 2, 4 , 8 ,10 ,16, 26這個序列要不要被考慮搜索呢?

開始覺得可能需要因為26直接由10,16計算來比較快到達26.

但其實

?

1? 2? 4? 8 16 24 26是一樣的
16 = u + a u = 8 a = 8
10 = u + b u = 8 b = 2
然后 1 2 4? u u+a u + u + a? u + u + a +b一樣能取到26長度不會更長。
所以證明成功,因為后面的序列如果之和10右關系則1,2 , 8 10可取代,如果只和16
有關系則1,2,4,8,16可以取代,而26的情況前面分析了也可以取代。所以,能剪掉很多枝。

另外可以用歸納法證明
對于到達任意數字的最短路徑。
當路徑長度為2的時候
a1 a2? (a2 = a1 + a1)
顯然成立
假設對于路徑長度為n的到任意數字的最短路徑成立,
那么對于n+1的最短路徑
如果不成立,即對an+1不符合歸則
則 a(n+1) = ai + aj; (i < n-1, j < n-1)
則到a(n+1)存在序列 a1, a2?? ai?? aj an+1符合要求
所以與原序列是最短路徑矛盾,得證。

這個證明的正確性不是很確定,呵呵,總之是可以剪枝了,不需要考慮那種情況了。

另外搜素的時候從大數字的分支優先搜索速度較快,因為大數字的分支內容較少,且容易較快的到達目的數字。

代碼如下

恩,發現用g++速度比c++慢很多0M->16M,恩以后都用c++提交:)

?這個題目也可以用BFS求解,16Ms,用open close表記錄已經出隊列的元素信息即可,需要的空間比較大。

?

//DFS 算法

#include <iostream> using namespace std; const int MaxNum = 100; int a[MaxNum]; //遞歸中的當前掃描路徑 int b[MaxNum]; //記錄當前找到的最短路徑 void PrintPath(int n) { for (int i = 0; i <= n; i++) cout << b[i] << " "; cout << endl; } int shortest_len = MaxNum; void FindShortestChian(int n, int i) { for (int j = i - 1; j >= 0; j--) { int sum = a[i - 1] + a[j]; if (sum == n) { a[i] = n; for (int k = 0; k <= i; k++ ) b[k] = a[k]; shortest_len = i; return; } else if (sum < n && i + 1 < shortest_len) { a[i] = sum; FindShortestChian(n, i+1); } } } int main(int argc, char *argv[]) { int n; a[0] = 1; a[1] = 2; b[0] = 1; b[1] = 2; while (1) { cin >> n; if (n == 0) break; else if (n == 1 || n == 2) PrintPath(n - 1); else { shortest_len = MaxNum; FindShortestChian(n, 2); PrintPath(shortest_len); } } return 0; }

?//BFS算法

?

#include <iostream> #include <stack> using namespace std; int Data[9000000]; int PreIndex[9000000]; //close 指向當前要處理的隊列元素,close前即為已經出隊列的 //open指向隊列尾部,即新加入元素要插入的位置 //close == open 表示隊列為空了 //data 數組存儲隊列元素數值 //index 數組存儲對應隊列元素的前驅元素的下標索引 void PrintPath(int close, int n) { stack<int> s; s.push(n); for (int i = close; i != -1; i = PreIndex[i]) s.push(Data[i]); while (!s.empty()) { cout << s.top() << " "; s.pop(); } cout << endl; } void FindShortestChian(int n) { Data[0] = 1; PreIndex[0] = -1; Data[1] = 2; PreIndex[1] = 0; int close = 1; int open = 2; while (close != open) { int a = close; int sum; while (a != -1){ sum = Data[close] + Data[a]; if (sum == n) { PrintPath(close, n); return; } else if (sum < n) { Data[open] = sum; //入隊列 PreIndex[open++] = close; //存前驅索引為當前處理元素index,open++ } a = PreIndex[a]; } close++; //當前元素處理完,出隊列 } } int main(int argc, char *argv[]) { int n; while (1) { cin >> n; if (n == 0) break; if (n == 1) cout << "1" << endl; else if (n == 2) cout << "1 2" << endl; else FindShortestChian(n); } return 0; }

?

?

?

轉載于:https://www.cnblogs.com/rocketfan/archive/2009/06/22/1508212.html

總結

以上是生活随笔為你收集整理的pku acm 2248 addtion chians 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。