題目大意: 給出一些大象,包含它的重量、智商。要你找出最長的序列,滿足重量越大、智商越低。(嚴格增減)
題目類型:dp / LIS
題目分析:
把大象按重量升序排序,然後在此序列中對智商屬性找最長單減子序列。要注意的是,題目要求的都是嚴格增減,所以要在判斷條件裡考慮相等的情況以排除(主要是重量)。
另外還要注意,排序後,序就不是原來的序了,而題目要求輸出原序。所以在排序時維護一個r[]數組。
對於 最長單減子序列 的dp,狀態轉移方程(2種):
//d[i] = max{d[j]+1 | s[i]>s[j]; j = (i, n);}//d[i] 表示以 i 開頭的 最長 遞減子序列
//d[i] = max{d[j]+1 | s[i]<s[j]; j = [0, i);}//d[i] 表示以 i 結尾的 最長 遞減子序列
代碼:
#include<cstdio><br />#include<cstring><br />#include<algorithm><br />using namespace std;<br />#define MAXN 1002<br />struct ele<br />{<br />int w, s;<br />int next;<br />int xh;<br />}e[MAXN];<br />int r[MAXN];//用於保留對應的原序<br />int n;<br />int d[MAXN];<br />int vis[MAXN];<br />//d[i] = max{d[j]+1 | s[i]>s[j]; j = (i, n);}//d[i] 表示以 i 開頭的 最長 遞減子序列<br />//d[i] = max{d[j]+1 | s[i]<s[j]; j = [0, i);}//d[i] 表示以 i 結尾的 最長 遞減子序列<br />int dp(int cur)//以cur,做開頭<br />{<br />if(vis[cur]) return d[cur];<br />vis[cur] = 1;<br />int max = 1;<br />for(int i=cur+1; i<n; i++)<br />if(e[i].s<e[cur].s && e[i].w>e[cur].w)//找降序//注意w 嚴格增 ②<br />{<br />int t = dp(i)+1;<br />max = max>t? max: (e[cur].next = i, t);<br />}<br />return d[cur] = max;<br />}<br />void print(int x)<br />{//d[x] = 1 說明 停止<br />while(1)<br />{<br />printf("%d/n", e[x].xh+1);//從1開始,④<br />///////////debug<br />//printf("w=%d, iq=%d/n", e[x].w, e[x].s);<br />if(d[x]==1) break;<br />x = e[x].next;<br />}<br />}<br />int cmp(ele a, ele b)//sort 中 參數 完全可以不用是 const 用於改值,很好用!③<br />{<br />if(a.w<b.w)<br />{<br />return 1;<br />}<br />else<br />{<br />int t = a.xh;<br />a.xh = b.xh;<br />b.xh = t;<br />return 0;<br />}<br />}<br />int main()<br />{<br />n=0;<br />for(int i=0; scanf("%d%d", &e[i].w, &e[i].s)!=EOF; i++, n++)<br />{<br />e[i].xh = i;<br />}<br />sort(e, e+n, cmp);//按 w 升序<br />memset(vis, 0, sizeof(vis));<br />int max = 1;<br />int ans;<br />for(int i=0; i<n; i++)<br />{<br />max = max > dp(i)? max: (ans = i, dp(i));<br />}<br />printf("%d/n", max);<br />print(ans);<br />}