[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;
}

浙公网安备 33010602011771号