#P2030. 交错匹配

#P2030. 交错匹配

题目描述

有两行自然数,UP[1..N],DOWN[1..M],如果UP[I]=DOWN[J]=K,那么上行的第I个位置的数就可以跟下行的第J个位置的数连一条线,称为一条K匹配,但是同一个位置的数最多只能连一条线。另外,每个K匹配都必须且至多跟一个L匹配相交且K≠L!现在要求一个最大的匹配数。 例如:以下两行数的最大匹配数为8

输入格式

第一行有两个正整数N和M。

第二行N个UP的自然数,第三行M个DOWN的自然数。其中0<N、M<=200,UP、DOWN的数都不超过32767。

输出格式

最大匹配数输出

样例

输入数据 1

12 11
1 2 3 3 2 4 1 5 1 3 5 10
3 1 2 3 2 4 12 1 5 5 3

输出数据 1

8

输入数据 2

4 4
1 1 3 3
1 1 3 3

输出数据 2

0

Solution

首先注意到,题目给定的数据规模不大,只有 \(200\) ,因此可以考虑用稍微暴力一点的算法。

提前预处理出与 \(down_i\) 相同的 \(up_i\) 的位置,存储在 \(same_i\) 中,然后 \(\text{DP}\)

\(f[i][j]\) 表示 \(up\)\(i\) 个和 \(down\)\(j\) 个能够构成的交错匹配数量。那么可以直接枚举交错匹配四个端点的位置,并尝试更新答案。

对于每个新的 \(f[i][j]\) ,答案可以从 \(f[i][j-1]\)\(f[i-1][j]\) 继承过来。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
 	k=0;
	T flag=1;char b=getchar();
	while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
	while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
	k*=flag;
}
const int _SIZE=2e2;
int n,m;
int up[_SIZE+5],down[_SIZE+5];
int same[_SIZE+5][_SIZE+5],f[_SIZE+5][_SIZE+5];
int main()
{
	read(n);read(m);
	for (int i=1;i<=n;i++) read(up[i]);
	for (int i=1;i<=m;i++) read(down[i]);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			if (up[i]==down[j]) same[j][++same[j][0]]=i;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
		{
			f[i][j]=max(f[i-1][j],max(f[i][j-1],f[i][j]));
			if (up[i]!=down[j]) continue;
			for (int k=j+1;k<=m;k++)
				if (down[k]==down[j]) continue;
				else for (int l=1;l<=same[k][0];l++)
					if (same[k][l]>=i) break;
					else f[i][k]=max(f[i][k],f[same[k][l]-1][j-1]+2);
		}
	printf("%d\n",f[n][m]);
	return 0;
}

posted @ 2022-07-11 11:22  Hanx16Msgr  阅读(25)  评论(0编辑  收藏  举报