【动态规划】Crossed Matchings

来源:互联网 发布:php 工厂模式 实例 编辑:程序博客网 时间:2024/04/19 09:09
Crossed Matchings
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 2079 Accepted: 1326

Description

There are two rows of positive integer numbers. We can draw one line segment between any two equal numbers, with values r, if one of them is located in the first row and the other one is located in the second row. We call this line segment an r-matching segment. The following figure shows a 3-matching and a 2-matching segment.

We want to find the maximum number of matching segments possible to draw for the given input, such that:
1. Each a-matching segment should cross exactly one b-matching segment, where a != b .
2. No two matching segments can be drawn from a number. For example, the following matchings are not allowed.

Write a program to compute the maximum number of matching segments for the input data. Note that this number is always even.

Input

The first line of the input is the number M, which is the number of test cases (1 <= M <= 10). Each test case has three lines. The first line contains N1 and N2, the number of integers on the first and the second row respectively. The next line contains N1 integers which are the numbers on the first row. The third line contains N2 integers which are the numbers on the second row. All numbers are positive integers less than 100.

Output

Output should have one separate line for each test case. The maximum number of matching segments for each test case should be written in one separate line.

Sample Input

36 61 3 1 3 1 33 1 3 1 3 14 41 1 3 3 1 1 3 3 12 111 2 3 3 2 4 1 5 1 3 5 103 1 2 3 2 4 12 1 5 5 3 

Sample Output

608

Source

Tehran 1999


这是一道我越优化越慢的题。。。
朴素打了一会儿直接就过了。。。
优化了半天,结果更慢了。。。


正常的是枚举最后一X,但是我比较菜嘛。。我枚举最后半X。。

如果是后半X则由前半X推过来。

如果是前半X则由前面任一后半X推过来。

方程比较菜。。。



优化到O(N^4)的最快的程序。(其实本来就是O(N^4),只是我比较菜,一开始打出来是O(N^5),后来把K滚动了)

#include <cstdio>#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))long num1[110];long num2[110];long f[110][110][110];int main(){freopen("cm.in","r",stdin);freopen("cm.out","w",stdout);long M;scanf("%ld",&M);while (M--){long N1;long N2;scanf("%ld%ld",&N1,&N2);for (long i=1;i<N1+1;i++)for (long j=1;j<N2+1;j++)for (long k=0;k<2;k++)f[i][j][k] = 0;for (long i=1;i<N1+1;i++)scanf("%ld",num1+i);for (long i=1;i<N2+1;i++)scanf("%ld",num2+i);long ans = 0;for (long i=1;i<N1+1;i++){for (long j=1;j<N2+1;j++){for (long k=0;k<2;k++){if ( k == 1 ){for (long p=1;p<i;p++)for (long q=1;q<j;q++)f[i][j][k] = MAX(f[i][j][k],f[p][q][k^1]);}else{if (num1[i] == num2[j]) continue;for (long p=1;p<i;p++)for (long q=1;q<j;q++)if (num1[p] == num2[j]&&num2[q] == num1[i])f[i][j][k] = MAX(f[i][j][k],f[p][q][k^1]+2);}ans = MAX(ans,f[i][j][k]);}}} printf("%ld\n",ans);}return 0;} 

优化到O(N^3),最慢的程序。预处理优化,预处理出数字为(num[i],num[j])的二元组(i,j)。枚举空间减少了很多。但是也许因为multimap本身效率低下的原因吧。等会儿看我改成二维数组。还有我的方程本来就不好,因此无法突破障碍吧。


一开始忘了初始化hash,还有忘记了判断取出来的是不是x<i且y<j。。主要就是类似于map这之类的长得不像数组的广义数组,一定要记得该初始化的地方要初始化


#include <cstdio>#include <map>#include <algorithm>#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))long num1[110];long num2[110];long f[110][110][110];struct Pair{long x;long y;Pair(long xx,long yy):x(xx),y(yy){}bool operator<(const Pair& p2)const{if(x==p2.x)return y<p2.y;return x<p2.x;}Pair(){}};using std::make_pair;using std::multimap;multimap<Pair,Pair> hash;multimap<Pair,Pair>::iterator it1;int main(){freopen("cm.in","r",stdin);freopen("cm.out","w",stdout);long M;scanf("%ld",&M);while (M--){long N1;long N2;scanf("%ld%ld",&N1,&N2);for (long i=1;i<N1+1;i++)for (long j=1;j<N2+1;j++)for (long k=0;k<2;k++)f[i][j][k] = 0;for (long i=1;i<N1+1;i++)scanf("%ld",num1+i);for (long i=1;i<N2+1;i++)scanf("%ld",num2+i);hash.clear();for (long i=1;i<N1+1;i++)for (long j=1;j<N2+1;j++)if (num1[i]-num2[j])hash.insert(make_pair(Pair(num1[i],num2[j]),Pair(i,j)));long ans = 0;Pair pos;for (long i=1;i<N1+1;i++){for (long j=1;j<N2+1;j++){for (long k=0;k<2;k++){if ( k == 1 ){for (long p=1;p<i;p++)for (long q=1;q<j;q++)f[i][j][k] = MAX(f[i][j][k],f[p][q][k^1]);}else{it1 = hash.find(Pair(num2[j],num1[i]));while (it1 != hash.end() && it1->first.x == num2[j]&& it1->first.y == num1[i]){if (it1->second.x < i && it1->second.y < j){pos = it1->second;f[i][j][k] = MAX(f[i][j][k],f[pos.x][pos.y][k^1]+2);}it1 ++;}}ans = MAX(ans,f[i][j][k]);}}} printf("%ld\n",ans);}return 0;} 


把上面那个改成二维数组了。Pair hash[101][101][801]是自己大概估计的,不敢大了,会爆空间。。。改了半天,速度终于和朴素一样了。。。


#include <cstdio>#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))long num1[110];long num2[110];long f[101][101][101];struct Pair{long x;long y;};Pair hash[101][101][801];long cnt[110][110];int main(){freopen("cm.in","r",stdin);freopen("cm.out","w",stdout);long M;scanf("%ld",&M);long N1=0;long N2=0;while (M--){for (long i=1;i<N1+1;i++)for (long j=1;j<N2+1;j++){cnt[num1[i]][num2[j]] = 0;for (long k=0;k<2;k++)f[i][j][k] = 0;}scanf("%ld%ld",&N1,&N2); for (long i=1;i<N1+1;i++)scanf("%ld",num1+i);for (long i=1;i<N2+1;i++)scanf("%ld",num2+i);for (long i=1;i<N1+1;i++)for (long j=1;j<N2+1;j++)if (num1[i]-num2[j]){hash[num1[i]][num2[j]][++cnt[num1[i]][num2[j]]].x = i;hash[num1[i]][num2[j]][cnt[num1[i]][num2[j]]].y = j;}long ans = 0;for (long i=1;i<N1+1;i++){for (long j=1;j<N2+1;j++){for (long k=0;k<2;k++){if ( k == 1 ){for (long p=1;p<i;p++)for (long q=1;q<j;q++)f[i][j][k] = MAX(f[i][j][k],f[p][q][k^1]);}else{for (long l=1;l<cnt[num2[j]][num1[i]]+1;l++){long x = hash[num2[j]][num1[i]][l].x;long y = hash[num2[j]][num1[i]][l].y;if (x<i && y<j)f[i][j][k] = MAX(f[i][j][k],f[x][y][k^1]+2);}}ans = MAX(ans,f[i][j][k]);}}} printf("%ld\n",ans);}return 0;} 


原创粉丝点击