1. 程式人生 > 遊戲攻略 >《破曉傳說》角色定位及實用技能推薦 角色培養方向介紹

《破曉傳說》角色定位及實用技能推薦 角色培養方向介紹

動態規劃簡介:動態規劃是在一個困難的 巢狀決策鏈 中,決策出最優解。動態規劃有 可推導性 ,但同時,動態規劃也有 無後效性 ,即 每個當前狀態會且僅會決策出下一狀態,而不直接對未來的所有狀態負責

子序列問題

首先宣告2個名詞:

$ \operatorname{LIS} $ :Longest Increasing Subsequence 最長遞增子序列

$ \operatorname{LCS} $ :Longest Common Subsequence 最長公共子序列

我們知道,用樸素的 $ \operatorname{DP} $ 解 $ \operatorname{LIS} $ 和 $ \operatorname{LCS} $ ,複雜度都是 \(O(n^2)\)

的,而且很容易寫出來。

for(int i=1;i<=n;i++)
{
	 dp[i]=1;
	 for(int j=1;j<i;j++)
	 if(val[j]<val[i] && dp[i]<dp[j]+1) dp[i]=dp[j]+1,pre[i]=j;
} // LIS

for(int i=1;i<=n;i++)
{
	 for(int j=1;j<=m;j++)
	 {
	 	 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
	 	 if(a[i]==b[j]) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
	 }
} // LAS

↑ 這便是極為低效的 \(O(n^2)\) 做法

考慮用 \(O(n log n)\) 演算法:用 \(dp[i]\) 表示在該序列中,上升子序列長度為 \(i\) 的上升子序列,的最小末尾數值。這樣可以二分求出比當前數值小的最長子序列。

$ \operatorname{LIS} $ 核心程式碼:

memset(dp,inf,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
{
	 if(val[i]>dp[ans]) dp[++ans]=val[i]; // 比之前最長的子序列的最大值還大,則 ans += 1 
	 else
	 {
	 	 int l=0,r=ans,ret=0;
	 	 while(l<r)
	 	 {
	 	 	 int mid=(l+r)/2;
	 	 	 if(dp[mid]<=val[i]) l=mid+1; // 找到第一個比 dp[...] 小的數 (這一題中是嚴格遞增)
	 	 	 else r=mid-1,ret=mid;
		 }
		 dp[l]=min(dp[l],val[i]);
	 }
}

在特殊條件下,即兩個序列的元素種類相同,可以用類似離散化的方式將一個序列變為 \(1…n\) 的序列,此時的 $ \operatorname{LCS} $ 就是另一個序列的 $ \operatorname{LIS} $ 則在這種條件下可以 \(O(nlogn)\) 地處理 $ \operatorname{LCS} $ 問題

$ \operatorname{LCS} $ 核心程式碼:

memset(dp,inf,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
{
	 if(Turn[b[i]]>dp[ans]) dp[++ans]=Turn[b[i]]; // 比之前最長的子序列的最大值還大,則 ans += 1 
	 else
	 {
	 	 int l=0,r=ans,ret=0;
	 	 while(l<r)
	 	 {
	 	 	 int mid=(l+r)/2;
	 	 	 if(dp[mid]<=Turn[b[i]]) l=mid+1; // 找到第一個比 Turn[b[i]] 小的數 
	 	 	 else r=mid-1,ret=mid;
		 }
		 dp[l]=min(dp[l],Turn[b[i]]);
	 }
}

LIS變形——平面吃豆子問題

題意:給定一張平面直角座標系,你現在處在 \((0,0)\) 的位置,而有些網格點上有豆子。如果你在 \((x,y)\) ,只能前往 \((x+1,y),(x,y+1),(x+1,y+1)\) 。請問最多能夠吃到多少顆豆子?

\(n\le 10^5,-10^9\le x_i,y_i \le 10^9\)

首先找出 \(x_i\ge 0,y_i\ge 0\) 的所有點,並對他們根據 \(x\) 為第一關鍵字,\(y\) 為第二關鍵字排序。

之後就對所有 \(y\) 跑一邊 \(\operatorname{LIS}\) 就可以啦

$\texttt{code}$
#define inf 0x3f3f3f3f
#define Maxn 100005
int n,m,ans,dp[Maxn];
struct Data { int x,y; }a[Maxn];
bool cmp(Data x,Data y)
{
	 if(x.x!=y.x) return x.x<y.x;
	 return x.y<y.y;
}
int main()
{
	 n=rd();
	 for(int i=1,x,y;i<=n;i++)
	 {
	 	 x=rd(),y=rd();
	 	 if(x<0 || y<0) { i--,n--; continue; }
	 	 a[i]=(Data){x,y};
	 }
	 sort(a+1,a+n+1,cmp);
	 memset(dp,inf,sizeof(dp)),dp[0]=0;
	 for(int i=1;i<=n;i++)
	 {
	 	 if(a[i].y>=dp[ans]) dp[++ans]=a[i].y;
	 	 else
	 	 {
	 	 	 int nl=0,nr=ans,mid,ret=0;
	 	 	 while(nl<=nr)
	 	 	 {
	 	 	 	 mid=(nl+nr)>>1;
	 	 	 	 if(dp[mid]<=a[i].y) nl=mid+1;
	 	 	 	 else nr=mid-1,ret=mid;
			 }
			 dp[ret]=min(dp[ret],a[i].y);
		 }
	 }
	 printf("%d\n",ans);
     return 0;
}