[考试]20150528
生活随笔
收集整理的這篇文章主要介紹了
[考试]20150528
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
// 此博文為遷移而來,寫于2015年6月6日,不代表本人現(xiàn)在的觀點與看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w3ai.html
?
1、前言 ???????我也是實在不能忍我的動態(tài)規(guī)劃水平了,所以要好好搞了。那么在狠狠補了許久的初級數(shù)據(jù)結(jié)構(gòu)以及學了一些新的高級數(shù)據(jù)結(jié)構(gòu)之后,現(xiàn)在開始把重點放在DP上。 ? 2、題目分析:考慮兩種方法。第一種為利用前綴和優(yōu)化轉(zhuǎn)移,f[i][j]表示從1到 i 選擇 j 個元素,即f[i][j]=max(f[k][j?1]+a[i])?(k<i-1),f[i][j]表示從1到 i 選擇 j 個元素,且最后一個元素必須選;g[i][j]表示從1到i-1選 j 個元素,即相比f[i][j]少了一個第 i 位。g[i][j]只是起一個輔助作用,意在選第 i 個和不選兩種情況下選擇最大值。 代碼: ---------------------------------------------------------------------------------------------------- #include<cstdio> #define MAXN 1005 #define INF 1<<30 ? typedef long long ll; ? ll max(ll a,ll b) { return (a>b)?a:b; } ? ll n,k,f[MAXN][MAXN],g[MAXN][MAXN],a[MAXN]; ? int main() { ????????freopen("a.in","r",stdin); ????????freopen("a.out","w",stdout); ????????scanf("%I64d %I64d",&n,&k); ????????for (int i=1;i<=k;i++) f[0][i]=g[0][i]=-INF; ????????for (int i=1;i<=n;i++) scanf("%I64d",&a[i]); ????????for (int i=1;i<=n;i++) ????????????????for (int j=1;j<=k;j++) ????????????????{ ????????????????????????f[i][j]=g[i-1][j-1]+a[i]; ????????????????????????g[i][j]=max(f[i-1][j],g[i-1][j]); ????????????????} ????????printf("%I64d",max(g[n][k],f[n][k])); }? ---------------------------------------------------------------------------------------------------- 注意:需要開long long。 ?
分析:靈感來源于最長公共子序列問題,用f[i][j]表示數(shù)組a的前i位和數(shù)組b的前j位能夠連線的條數(shù)。根據(jù)題意不難發(fā)現(xiàn),線只存在兩種情況——一條線單獨存在;兩條線交叉。即: ???????????1、a[i]=b[j] 時,f[i][j]=f[i-1][j-1]+1; ???????????2、a[i]≠b[j]時,又存在三種情況:f[i][j]=max(f[x][y]+2,f[i-1][j],f[i][j-1])。上述的x,y分別表示b[j]的數(shù)值在數(shù)組a的位置,a[i]的數(shù)值在數(shù)組b的位置。 ???????????x,y?預(yù)處理于兩個數(shù)組中。需注意,必須滿足x小于i,y小于j,因為后面的狀態(tài)你還沒算到呢(我想了好久為什么 = =。。) ? 代碼: ----------------------------------------------------------------------------------------------------- #include<cstdio>
#define MAXN 1005 int max(int a,int b) { return (a>b)?a:b; } int temp[MAXN],link[MAXN],f[MAXN][MAXN],numa[MAXN],numb[MAXN],n,a[MAXN],b[MAXN]; int main()
{ ?????????freopen("b.in","r",stdin);
?????????freopen("b.out","w",stdout);
?????????scanf("%d",&n);
?????????for (int i=1;i<=n;i++) { scanf("%d",&a[i]); numa[a[i]]=i; }
?????????for (int i=1;i<=n;i++) { scanf("%d",&b[i]); numb[b[i]]=i; }
?????????for (int i=1;i<=n;i++)
?????????for (int j=1;j<=n;j++)
?????????{
?????????????????if (a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
?????????????????else?
?????????????????{
?????????????????????????f[i][j]=max(f[i][j-1],f[i-1][j]);
?????????????????????????if (numa[b[j]]<i && numb[a[i]]<j) f[i][j]=max(max(f[numa[b[j]]][numb[a[i]]]+2,f[i-1][j]),f[i][j-1]);
?????????????????}
????????}
???????printf("%d",f[n][n]);
???????return 0;
} ---------------------------------------------------------------------------------------------------- ? c題跳過。 ?
分析:這樣題看起來比較麻煩,其實如果巧妙地利用好相對論,寫出來的狀態(tài)轉(zhuǎn)移方程比a題還簡單。。。然而這種題最難想出來了。我們假設(shè)數(shù)組最大值n,放在數(shù)組a[i]上。則若n-1在n的前面,則n-1必須為第一位,否則則可以放在任意位置。不然的話,最長上升子序列必定存在長度大于2的情況。根據(jù)這條規(guī)律,我們可以向前遞歸——若n-1在n的前面,我們考慮n-2和n的位置關(guān)系。若n-2又在n的前面,則n-2只能為第二位,若n-2在n的后面,則任意位置都行;若n-1在n的后面,我們考慮n-2和n-1的位置關(guān)系。。等等,有點扯不清了,等下再補充。 ? P.S. 本頁兩個bug:這套試題是2015年5月28日考的;第二題輸入格式和數(shù)據(jù)范圍都有點小問題但并不重要。
轉(zhuǎn)載于:https://www.cnblogs.com/jinkun113/p/4682869.html
總結(jié)
以上是生活随笔為你收集整理的[考试]20150528的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【LeetCode】70 - Climb
- 下一篇: Git命令小记