http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1425
DP,定义dp[i][j]为第一行中的前i个数和第二行中的前j个数,最多能构成多少对相交线段。因为题意中规定,任意一段合法的线段a有且只有一段线段b与之相交,且a!=b,由此可得:在这段线段之间将不会有其他新的线段了,因此可以定义转移方程为:
dp[i][j] = max{ dp[ii-1][jj-1] + 2 , dp[i-1][j] , dp[i][j-1] } ,其中a[ii] == b[j] && b[jj] == a[i] ,其中对于最后两个的解释是,a[i] 和 b[j] 都不参与构成相交线段。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define max(a,b) (a>b?a:b) using namespace std; int n,m; int a[101],b[101] ; int dp[101][101] ; int DP() { int ii,jj,i,j; memset(dp,0,sizeof(dp)); for(i=2;i<=n;i++) { for(j=1;j<=m;j++) { if(j==1) continue ; for(jj=j-1;jj>=1;jj--) //寻找a[i] == b[jj]的点 { if(a[i] == b[jj]) break ; } for(ii=i-1;ii>=1;ii--) //寻找b[j] == a[ii]的点 { if(b[j] == a[ii]) break ; } if(jj==0 || ii==0) { dp[i][j] = max(dp[i-1][j] ,dp[i][j-1]) ; } else{ dp[i][j] = max(dp[i-1][j] ,dp[i][j-1]) ; if(a[i] != b[j]) dp[i][j] = max(dp[i][j] ,dp[ii-1][jj-1]+2) ; } } } return dp[n][m] ; } int main() { //freopen("1in.txt","r",stdin); //freopen("1out.txt","w",stdout); int T; scanf("%d",&T) ; while(T--) { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) scanf("%d",&b[i]); int ans = DP(); printf("%d\n",ans); } return 0; }