2019.10.25字符串——zr

题意:

给你两个字符串,由01组成;求他们两个的最短公共非子序列,要求字典序最小;

非公共子序列:都不是这两个字符串的子序列;

本人只会暴力啊,二进制枚举稳拿15分;

然而这道题其实是一个最短路题;

题解:

贪心考虑从前往后s1……si,维护一个j表示当前字符串已经匹配到t1……tj,

贪心考虑tj'=si+1的j'匹配;

要求字典序最小,实际上我们求得就是一个最短路;

从中止状态反向遍历,就可以记录哪些点在起点到终点的最短路上。DP的状态就是最短路;

再从开始点开始,哪个状态在最短路上,就输出;

时间复杂度(n2);

我觉得吧,其实就是在这两个字符串上找到最短的公共子串(感性理解,实际上并不是这个意思),我们要匹配到n+1,m+1,一个串结束了,并不代表状态的结束;

因为当前状态+0/1可能还是较长串的子序列;

当我们匹配到n+1,m+1的时候就是最短非公共子序列;

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=4010;
 6 int n,m;
 7 char s[maxn],t[maxn];
 8 
 9 int nxt_s[maxn][2],nxt_t[maxn][2];
10 
11 int dp[maxn][maxn];
12 
13 int on_road[maxn][maxn];
14 
15 int main()
16 {
17     scanf("%d%d",&n,&m);
18     scanf("%s%s",s+1,t+1);
19     nxt_s[n+1][0]=nxt_s[n+1][1]=n+1;
20     for(int i=n;i>=1;i--)
21     {
22         int c=s[i]-'0';
23         nxt_s[i][c]=i;
24         nxt_s[i][c^1]=nxt_s[i+1][c^1];
25     }
26     nxt_t[m+1][0]=nxt_t[m+1][1]=m+1;
27     for(int i=m;i>=1;i--)
28     {
29         int c=t[i]-'0';
30         nxt_t[i][c]=i;
31         nxt_t[i][c^1]=nxt_t[i+1][c^1];
32     }
33     
34     memset(dp,0x3f,sizeof(dp));
35     dp[0][0]=0;
36     for(int i=0;i<=n+1;i++)
37     {
38         for(int j=0;j<=m+1;j++)
39         {
40             for(int c=0;c<2;c++)
41             {
42                 int x=i<=n?nxt_s[i+1][c]:i;
43                 int y=j<=m?nxt_t[j+1][c]:j;
44                 if(dp[x][y]>dp[i][j]+1)
45                 {
46                     dp[x][y]=dp[i][j]+1;
47                 }
48             }
49         }
50     }
51     
52     on_road[n+1][m+1]=1;
53     for(int i=n+1;i>=0;i--)
54     {
55         for(int j=m+1;j>=0;j--)
56         {
57             for(int c=0;c<2;c++)
58             {
59                 int x=i<=n?nxt_s[i+1][c]:i;
60                 int y=j<=m?nxt_t[j+1][c]:j;
61                 if(dp[x][y]==dp[i][j]+1&&on_road[x][y])
62                 {
63                     on_road[i][j]=1;
64                 }
65             }
66         }
67     }
68     
69     int i=0,j=0;
70     
71     while(i<=n||j<=m)
72     {
73         for(int c=0;c<2;c++)
74         {
75             int x=(i<=n?nxt_s[i+1][c]:i);
76             int y=(j<=m?nxt_t[j+1][c]:j);
77             if(dp[x][y]==dp[i][j]+1&&on_road[x][y])
78             {
79                 putchar(c+'0');
80                 i=x;j=y;
81                 break;
82             }
83         }
84     }
85     
86     return 0;
87 }
View Code

猜你喜欢

转载自www.cnblogs.com/WHFF521/p/11739400.html