【 OJ 】 HDOJ1025 18年11月08日19:07 [ 24 ]
ummmm ,題目還是很好理解的,道路只要不交叉就可以了,那麼很顯然只要r(富裕)城市一直保持遞增就好了,因為p(貧窮)城市是正常的123...n 的遞增排列
首先拿到這題第一思路就是DP:
陣列都開的比較小,因為題目50W的城市時間複雜度穩掛....
然後現在....去看別人程式碼學習.....二分之類的O(nlogn)
ummmm
# include<iostream> using namespace std; int p[100]; int r[100]; int dp[100]; void Out(int n,int sum) { cout << "Case " << n << ":" << endl; cout << "My king, at most " << sum << " road can be built."<<endl; } int main(void) { int n;//城市數目 int out_time = 1; bool ISok = true; while (cin >> n) { if (!ISok) { cout << endl; ISok = false; } for (int i = 0; i < n; ++i) { cin >> p[i] >> r[i];//先p後r }//錄入資料 dp[0] = 1; for (int i = 1; i < n; ++i) { dp[i] = 1; for (int j = 0; j < i; j++) { if (r[i] > r[j]&&dp[i]<=dp[j]) { dp[i] = dp[j] + 1; } } }//dp處理 int max=0; for (int i = 0; i < n; ++i) { if (dp[i] > max) max = dp[i]; } Out(out_time++, max); ISok = false; } system("pause"); return 0; }
轉載請註明原文地址:https://www.cnblogs.com/GodA/p/5180560.html
這個講解的感覺帶著例項好理解一點....
我們舉一個例子:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS長度。
我們定義一個B[i]來儲存可能的排序序列,len為LIS長度。我們依次把A[i]有序地放進B[i]裡。(為了方便,i的範圍就從1~n表示第i個數)
A[1]=3,把3放進B[1],此時B[1]=3,此時len=1,最小末尾是3
A[2]=1,因為1比3小,所以可以把B[1]中的3替換為1,此時B[1]=1,此時len=1,最小末尾是1
A[3]=2,2大於1,就把2放進B[2]=2,此時B[]={1,2},len=2
同理,A[4]=6,把6放進B[3]=6,B[]={1,2,6},len=3
A[5]=4,4在2和6之間,比6小,可以把B[3]替換為4,B[]={1,2,4},len=3
A[6]=5,B[4]=5,B[]={1,2,4,5},len=4
A[7]=10,B[5]=10,B[]={1,2,4,5,10},len=5
A[8]=7,7在5和10之間,比10小,可以把B[5]替換為7,B[]={1,2,4,5,7},len=5
最終我們得出LIS長度為5。但是,但是!!這裡的1 2 4 5 7很明顯並不是正確的最長上升子序列。是的,B序列並不表示最長上升子序列,它只表示相應最長子序列長度的排好序的最小序列。這有什麼用呢?我們最後一步7替換10並沒有增加最長子序列的長度,而這一步的意義,在於記錄最小序列,代表了一種“最可能性”。假如後面還有兩個資料8和9,那麼B[6]將更新為8,B[7]將更新為9,len就變為7。讀者可以自行體會它的作用。
我的程式碼沒有AC顯示.Time Limit Exceeded 吐血= =~
# include<iostream>
#include <algorithm>
using namespace std;
int p[500002];//規模不超過50W
int r[500002];
int sq[500002];//需要維護的陣列
void Out(int n, int sum) {
cout << "Case " << n << ":" << endl;
cout << "My king, at most " << sum << " road"<<((sum>1)?"s":"")<<" can be built." << endl<<endl;
}
//貪心+二分 時間複雜度O(nlogn) 二分用STL中的lowder_bound 實現
int main(void) {
int n;//城市數目
int index;
int time = 0;
while (cin >> n) {
time++;
index = 0;
fill(sq, sq + n, 0);
for (int i = 0; i < n; ++i) {
cin >> p[i] >> r[i];//先p後r
}//錄入資料
sq[index] = r[0];
for (int i = 1; i < n; i++) {
if (r[i] >= sq[index]) {
sq[++index] = r[i];//比他大就繼承
}
else {
*lower_bound(sq, sq + index+1, r[i])=r[i];//從sq到sq+n 二分查詢第一個大於或等於r[i]的數,返回地址賦值r[i]
}
}
Out(time, index+1);
}
system("pause");
return 0;
}