p1248【交错匹配】(DP)

    

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

输入格式 Input Format
第一行有两个正整数N和M。第二行N个UP的自然数,第三行M个DOWN的自然数。其中0<N、M<=200,UP、DOWN的数都不超过32767。


输出格式 Output Format
一个整数:最大匹配数


样例输入 Sample Input
样例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

样例2:
4 4
1 1 3 3
1 1 3 3


样例输出 Sample Output
样例1:
8

样例2:
0


时间限制 Time Limitation
2s


注释 Hint
2s


来源 Source
经典问题

       就是一道DP问题,以为数据比较小就是一个双进程的DP裸题。因为你要求出交错的最多数,所以我们认为上面的数列为a[i],下面则为b[i];

       而你要使数列上下匹配得到的两两交叉最多,所以要使交叉最多。我们可以用两重循环枚举两个队列里面的所有数,假设枚举到a[i],则在

       b[]数组中从i开始前找最近的和a[i]相等的数然后返回这个数字的位置即可。这样我们状态转移方程f[i][j]就和f[i-1][j],f[i-1][j-1],f[x-1][y-1],所以

       直接求最大值就行了

       

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 int a[310],b[310];
 8 int dp1[310][310],dp2[310][310];
 9 int f[310][310];
10 int work(int c[],int now,int v)
11 {
12     for(int i=now-1;i>=1;i--)
13         if(c[i]==v)
14             return i;
15     return 0;
16 }
17 int main()
18 {
19     int n,m;
20     cin>>n>>m;
21     for(int i=1;i<=n;i++)
22         cin>>a[i];
23     for(int i=1;i<=m;i++)
24         cin>>b[i];
25     memset(f,0,sizeof(f));
26     for(int i=1;i<=n;i++)
27     {
28         for(int j=1;j<=m;j++)
29         {
30             f[i][j]=max(f[i][j-1],f[i-1][j]);
31             if(a[i]==b[j])
32                 continue;
33             int x=work(a,i,b[j]);
34             int y=work(b,j,a[i]);
35             if(x>0&&y>0)
36             {
37                 f[i][j]=max(f[i][j],f[x-1][y-1]+2);
38             }
39         }
40     }
41     cout<<f[n][m]<<endl;
42     return 0;
43 }
|ω・`)暗中观察

 

posted @ 2017-08-21 10:52  列車員lcy  阅读(458)  评论(0编辑  收藏  举报