今天做了兩個DP的題目,只要掌握了方法,基本上都是水題。下面簡單說一下:傳送門(點擊打開鏈接)
A - Prince and Princess
思路:
求最長公共子序列,只不過數據較大,不能直接求,而是將LCS問題進行轉換爲LIS問題,求最長上升子序列即可。
如何轉化?:
最長公共子序列向最長遞增子序列退化:
設有序列A,B。記序列A中各個元素在B 中的位子(降序排列),然後按在A中的位置依次列出按後求A的最長遞增子序列。
例如:有A={a,b,a,c,x},B={b,a,a,b,c,a}則有a={6,3,2},b={4,1},c={5};x=/;(注意降序排列)
然後按A中次序排出{a(6,3,2),b(4,1),a(6,3,2),c(5),x()}={6,3,2,4,1,6,3,2,5};對此序列求最長遞增子序列即可(轉自:點擊打開鏈接)
代碼:
#include <bits/stdc++.h>
using namespace std;
const int M = 100000;
int n,p,q;
int len;
int low[M],a[M],b[M],num[M];
int main()
{
int t;
int cas = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&n,&p,&q);
memset(num,-1,sizeof(num));
for(int i=0;i<=p;i++)
{
scanf("%d",&a[i]);
num[a[i]] = i; //LCS轉換爲LIS所用記錄位置的數組
}
int cnt = 0;
int m;
for(int i=0;i<=q;i++)
{
scanf("%d",&m);
if(num[m]!=-1)
{
b[cnt++]=num[m]; //處理之後,直接求b的最長上升子序列即可
}
}
len = 0; //下面是二分找最長上升子序列
memset(low,0,sizeof(low));
low[0] = b[0];
for(int i=1;i<cnt;i++)
{
if(b[i]>low[len])
{
low[++len] = b[i];
}
else
{
int p = lower_bound(low,low+len,b[i])-low;
low[p] = b[i];
}
}
printf("Case %d: %d\n",cas,len+1);
cas++;
}
return 0;
}
E - Partitioning by Palindromes
題意:給你一個串進行劃分,問最少可以分成幾個迴文串。
思路:
暴力枚舉每一部分,然後進行比較,取最小的,詳見代碼:
#include <bits/stdc++.h>
using namespace std;
int dp[1005];
char s[1005];
int main()
{
int t;
int flag;
scanf("%d",&t);
while(t--)
{
cin>>s;
int len = strlen(s);
memset(dp,0x3f,sizeof(dp));
dp[0] = 1;
for(int i=1; i<=len-1; i++) //以i爲結尾
{
for(int j=0;j<=i;j++) //以j爲起點的
{
flag = 1;
for(int k=0;k<=(i-j)/2;k++) //每一段區間是否形成迴文串
{
if(s[i-k]!=s[j+k])
{
flag = 0;
break;
}
}
if( flag == 1) //若形成了,在j的基礎上加一操作
{
if(dp[ i ] > dp [ j - 1] + 1)
{
dp[ i ] = dp[ j - 1 ] + 1; //找最小
}
}
}
}
printf("%d\n" , dp[len-1]);
}
return 0;
}