POJ1692 Crossed Matchings
来源:互联网 发布:防止mysql 注入攻击 编辑:程序博客网 时间:2024/04/26 11:23
Crossed Matchings
Description
给定两个正整数数列,如果第一个数列中有一个数和第二个数列中的某个数相同,并且都为r,则我们可以将这两个数用线段连起来。我们称这条线段为 r-匹配线段。
我们想要对于给定的输入,找到画出最多匹配线段的方式,并且满足以下条件:
每条a-匹配线段恰好和一条b-匹配线段相交,且a
≠ b。我们称这样的匹配为交叉匹配。不允许一点多线和一线多交的情况出现:不允许两条线段从同一个数出发,不允许一条线段和多条其它线段相交。
编一个程序对于给定输入数据,计算匹配线段的最多条数。
Sample Input
3
6 6
1 3 1 3 1 3
3 1 3 1 3 1
4 4
1 1 3 3
1 1 3 3
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
Sample Output
6
0
8
本题重点在于如何通过推导和约束,实现时间复杂度的降维。本题的基本推导思想亦借鉴于模板型线性dp:LIS,LCS,LCIS等的推导方法。
首先根据题意,我们要定义
首先我们可以得到最简单的做法:
- 欲匹配
ai,bj ,于是在a[1...i−1] 中找到ak=bj ,b[1...j−1] 中找到bp=ai ,用当前枚举的{k,p} 内的最大值去更新dp[i][j] 。转移方程式:此时复杂度为dp[i][j]=max⎧⎩⎨⎪⎪⎪⎪⎪⎪max{dp[i−1][j]dp[i][j−1]dp[k−1][p−1]+2ak=bj,bp=ai O(n4) ,非常暴力。
接下来进一步考虑优化,我此时借鉴了LCIS
套用LCIS的思路,对于这个
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;static const int M=1005;int n,m,a[M],b[M];int dp[M][M];void check(int &a,int b){if(a<b)a=b;}int main(){ 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]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++)dp[i][j]=dp[i-1][j]; for(int k=1;k<i;k++) if(a[i]!=a[k]){ int mx=0;//局部变量,表示收集所有a[i]=b[j]时最大dp[k-1][p-1] for(int j=1;j<=m;j++){ check(dp[i][j],dp[i][j-1]); if(a[i]==b[j])check(mx,dp[k-1][j-1]+2); else if(a[k]==b[j])check(dp[i][j],mx); } } } printf("%d\n",dp[n][m]);}
之后想了一段时间,意识到这样一个小贪心:由于定义
于是对于
综上,转移方程式为
Code:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define clear(x,val) memset(x,val,sizeof(x))static const int M=2005;int n,m,a[M],b[M];int res[M<<1],rtop=0;int Top[M<<1],dp[M][M];void check(int &a,int b){if(a<b)a=b;}int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]),res[++rtop]=a[i]; for(int i=1;i<=m;i++)scanf("%d",&b[i]),res[++rtop]=b[i]; sort(res+1,res+rtop+1); rtop=unique(res+1,res+rtop+1)-(res+1); for(int i=1;i<=n;i++)a[i]=lower_bound(res+1,res+rtop+1,a[i])-res; for(int i=1;i<=m;i++)b[i]=lower_bound(res+1,res+rtop+1,b[i])-res; clear(Top,-1); for(int i=1;i<=n;i++){ int pre=-1; for(int j=1;j<=m;j++){ check(dp[i][j],dp[i-1][j]); check(dp[i][j],dp[i][j-1]); if(b[j]==a[i])pre=j; else if(Top[b[j]]!=-1&&pre!=-1) check(dp[i][j],dp[Top[b[j]]-1][pre-1]+2); } Top[a[i]]=i; } printf("%d\n",dp[n][m]);}
- ZOJ1425 POJ1692 Crossed Matchings
- POJ1692:Crossed Matchings
- POJ1692 Crossed Matchings
- POJ1692 Crossed Matchings DP
- POJ1692 Crossed Matchings(dp)
- 北大ACM poj1692 Crossed Matchings(动态规划)
- POJ1692————Crossed Matchings(动态规划)
- poj1692 Crossed Matchings(dp,最长公共子序列变形,好题)
- PKU1692 Crossed Matchings
- POJ 1692 Crossed Matchings
- pku1692 Crossed Matchings
- poj 1692 Crossed Matchings
- 【动态规划】Crossed Matchings
- ZOJ1425 Crossed Matchings dp
- zoj 1425 Crossed Matchings
- Crossed Matchings zoj1425 dp
- POJ 1692 Crossed Matchings
- POJ 1692 Crossed Matchings
- HDU 5119 Happy Matt Friends 递推
- C++的Enum hack
- 相信未来
- w的阶乘里有多少个p
- MFC(一)——WINDOWS消息机制
- POJ1692 Crossed Matchings
- [luogu2409]Y的积木(dp)
- Git和Github简单教程
- Pointers on C 重点笔记 第二章
- softlockup检测(watchdog)原理
- 跨层寻路
- web.xml中load-on-startup的作用
- Opencv中使用Rect的函数创建按钮和文字
- APUE笔记---第四章Linux文件系统与文件目录操作