[USACO17FEB]Why Did the Cow Cross the Road II

做题时间:2021.03.20

\(【题目描述】\)

按顺序给出 \(N(N\leq 10^3)\) 个点两组 \(a_1,...,a_n\)\(b_1,...,b_n\) ,它们的编号分别是 \([1,n]\) 的一个排列,定义合并操作为:在 \(|a_i-b_j|\leq 4\)\(a_i\)\(b_j\) 都没有被合并过的前提下, \(a_i\)\(b_j\) 能够连接,它们之间会连接上一条边,之后的所有合并操作的边都不能与之相交。问最多能够进行多少次合并操作。

\(【输入样例】\)

6
1 2 3 4 5 6
6 5 4 3 2 1

\(【输出样例】\)

5

\(【考点】\)

动态规划

\(【做法】\)

定义\(f_{i,j}\)表示当前匹配完了第一组点的前\(i\)个,第二组的前\(j\)个的最大合并次数。

很容易得出转移方程:

\[f_{i,j}=\max(f_{i-1,j-1}+1,f_{i-1,j}+1,(f_{i-1,j-1}+1)\cdot [|a_i-b_j|\leq 4]) \]

\(【代码】\)

#include<cstdio>
#include<iomanip>

using namespace std;
const int N=1e3+50;
int f[N][N];
int a[N],b[N];
int n;
inline int Max(int a,int b){return a>b?a:b;}
inline int Abs(int a)
{
	if(a<0) return -a;
	return a;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			f[i][j]=Max(f[i-1][j],f[i][j-1]);
			if(Abs(a[i]-b[j])<=4) f[i][j]=Max(f[i][j],f[i-1][j-1]+1);
		}
	}
	printf("%d\n",f[n][n]);
	return 0;
}
posted @ 2021-03-22 12:56  lxzy  阅读(59)  评论(0)    收藏  举报