D. Flood Fill 区间DP 或lcs匹配

题意 给定一串数字 相同的连续的数字可以同时 转换成一个相同数字 问最小几次可以全部转换成一个相同的数字

法1:区间dp  dp[l][r][0/1]  0表示l r区间转化成和最左边相同需要多少次 1表示转化成和最右边相同 区间dp即可

 1 #include<bits/stdc++.h>
 2 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++)
 3 #define MS(arr,arr_value) memset(arr,arr_value,sizeof(arr)) 
 4 #define F first 
 5 #define S second
 6 #define pii pair<int ,int >
 7 #define mkp make_pair
 8 #define pb push_back
 9 using namespace std;
10 typedef long long ll;
11 const int maxn=5e3+4;
12 int c[maxn],a[maxn],b[maxn];
13 int dp[maxn][maxn][2];
14 int main(){
15     int n;
16     MS(dp,0x3f3f3f3f);
17     scanf("%d",&n);
18     FOR(i,1,n)scanf("%d",&c[i]);
19     int cnt=0;
20     int p=1;
21     while(p<=n){
22         if(c[p]!=c[p-1]||p==1)a[++cnt]=c[p];
23         p++;
24     }
25     for(int i=1;i<=cnt;i++){
26         dp[i][i][0]=dp[i][i][1]=0;
27     }
28     for(int len=1;len<=cnt;len++){
29         for(int l=1,r=len+l;r<=cnt;r++,l++){
30             dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][0]+1);
31 
32             dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][1]+!(a[r]==a[l]));
33 
34             dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][1]+1);
35 
36             dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][0]+!(a[l]==a[r]));
37         }
38     }
39     cout<<min(dp[1][cnt][0],dp[1][cnt][1])<<endl;
40     return 0;
41 }
View Code

法2:LCS   从题目可以看出 如果转换成n个互相不连续的数字之后,如果所有数字都不相同则需要转换n-1次才能转换成一种答案

如果存在 例如1 2 3 4 2 5   有区间[2,5] 这时如果先转化2 5 之间的数字 即可少转化一次 那么问题就转换成 求最大不相交的这种区间有多少个(相交不行,因为相交 中间夹的那个点就被更改了)

而求最大相交的区间有多少个 就是把原序列翻转后的序列和原序列求lcs 因为lcs配对的过程  在原序列中的i  和翻转序列的j 就相当于 在原序列左右两边配对 所以不会相交 而因为是翻转的序列 所以会求两遍

所以要/2 并且有一个区间的左右是重合的也就退化成了一个点,不能算 (这里在除以2的时候已经被消气了)减1 是因为 没有区间的时候是n-1的,每多一个区间都可以-1 这样答案就是总共的点数n-1-floor(lcs(s)/2);

 1 #include<bits/stdc++.h>
 2 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++)
 3 #define MS(arr,arr_value) memset(arr,arr_value,sizeof(arr)) 
 4 #define F first 
 5 #define S second
 6 #define pii pair<int ,int >
 7 #define mkp make_pair
 8 #define pb push_back
 9 using namespace std;
10 typedef long long ll;
11 const int maxn=5e3+4;
12 int c[maxn],a[maxn],b[maxn];
13 int dp[maxn][maxn];
14 int main(){
15     int n;
16     scanf("%d",&n);
17     FOR(i,1,n)scanf("%d",&c[i]);
18     int cnt=0;
19     int p=1;
20     while(p<=n){
21         if(c[p]!=c[p-1]||p==1)a[++cnt]=c[p];
22         p++;
23     }
24     memcpy(b,a,sizeof(a));
25     reverse(b+1,b+cnt+1);
26 //    for(int i=1;i<=cnt;i++)cout<<b[i]<<" ";
27 //    puts("");
28     for(int i=1;i<=cnt;i++){
29         for(int j=1;j<=cnt;j++)
30         {
31             if(a[i]==b[j]){
32                 dp[i][j]=dp[i-1][j-1]+1;
33             }
34             else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
35         }
36     }
37     printf("%d
",cnt-1-dp[cnt][cnt]/2);
38     return 0;
39 }
View Code

   

两种方法参考:https://www.cnblogs.com/pkgunboat/p/10361375.html

区间dp 参考:https://blog.csdn.net/moon_sky1999/article/details/87171499

原文地址:https://www.cnblogs.com/ttttttttrx/p/10585266.html