完全自己写出来的DP,好开心QvQ
原题:
有两行自然数,UP[1..N],DOWN[1..M],如果UP[I]=DOWN[J]=K,那么上行的第I个位置的数就可以跟下行的第J个位置的数连一条线,称为一条K匹配,但是同一个位置的数最多只能连一条线。另外,每个K匹配都必须且至多跟一个L匹配相交且K≠L 。现在要求一个最大的匹配数。
例如:以下两行数的最大匹配数为8
0<N、M<=200
最开始考虑怎么转移,从左往右转移,从右往左转移,两行分别设一个f然后取最小值……
然后怎么搞都不行啊
认真思考两天颓了一中午看动漫后,突然灵光一闪就莫名奇妙get到做法了
既然是双进程,就开个二维数组,完全排除两条线之间乱七八糟的干扰
然后在每个决策点(i,j)从1到i-1找一个点p,在从1到j-1找一个点q,如果i,j,p,q能形成一个交错匹配,f[i][j]=max(f[i][j],f[p-1][q-1]+1);
还有一个问题就是每次到一个决策点(i,j)的时候这个决策点的初始值应该是(1到i-1,1到j-1)的最优质,刚开始的时候写的是在开始的时候f[i][j]=max(f[i-1][j-1],max(f[i-1][j],f[j][i-1])),然后WA了,不知道为什么酱紫不能把前面所有的最优状态转移过去
cydiater大神的思路似乎和我不一样,而且我做的时候找交错匹配的时候是直接枚举找,用个东西存一下复杂度会更低,然而数据太水我枚举也很快过了一。一
差点就看题解了,看题解的话就没有锻炼机会了
如果DP的时候没有思路或会遇到很多乱七八糟的东西干扰状态的话,可以开多维将干扰状态的东西也设成一维状态
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int n,m,a[210],b[210]; 8 int f[210][210]; 9 int main(){//freopen("ddd.in","r",stdin); 10 memset(f,0,sizeof(f)); 11 cin>>n>>m; 12 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 13 for(int i=1;i<=m;i++) scanf("%d",&b[i]); 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=m;j++){ 16 for(int p=1;p<=i;p++) 17 for(int q=1;q<=j;q++) 18 f[i][j]=max(f[i][j],f[p][q]);//不知道为什么不能直接取f[i-1][j-1],f[i-1][j],f[i][j-1]的最大值 19 if(a[i]!=b[j]){ 20 for(int p=1;p<i;p++)if(a[p]==b[j]) 21 for(int q=1;q<j;q++)if(b[q]==a[i]){ 22 f[i][j]=max(f[i][j],f[p-1][q-1]+1); 23 //cout<<i<<" "<<j<<" "<<p<<" "<<q<<endl; 24 } 25 } 26 } 27 cout<<f[n][m]*2<<endl; 28 return 0; 29 }