2016_特长生
三、字串距离
【问题描述】
设有字符串 X,我们称在 X 的头尾及中间插入任意多个空格后构成的新字符
串为 X 的扩展串,如字符串 X 为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd
□”和“abcb□cd□”都是 X 的扩展串,这里“□”代表空格字符。
如果 A1 是字符串 A 的扩展串,B1 是字符串 B 的扩展串,A1 与 B1 具有相
同的长度,那么我扪定义字符串 A1 与 B1 的距离为相应位置上的字符的距离总
和,而两个非空格字符的距离定义为它们的 ASCII 码的差的绝对值,而空格字
符与其他任意字符之间的距离为已知的定值 K,空格字符与空格字符的距离为 0。
在字符串 A、B 的所有扩展串中,必定存在两个等长的扩展串 A1、B1,使得 A1
与 B1 之间的距离达到最小,我们将这一距离定义为字符串 A、B 的距离。
请你写一个程序,求出字符串 A、B 的距离。
【数据输入】
从文件blast.in中读入数据,输入文件第一行为字符串A,第二行为字符串B。 A、B 均由小写字母组成且长度均不超过 2000。第三行为一个整数 K(1≤K≤100),
表示空格与其他字符的距离。
【数据输出】
输出到文件 blast.out 中,仅一行包含一个整数,表示所求得字符串 A、B 的
距离。
【输入输出样例】
blast.in
cmc
snmn
2
blast.out
10
思路:DP
假设 f [ i ] [ j ] f[i][j] f[i][j]为A串前 i i i个与B串前 j j j个相匹配…………
则会出现三种情况:
f i r s t first first:
A[i]与B[j]相匹配,求距离,再加A串 i i i前与B串 j j j前的数相匹配的最优值
s e c o n d second second:
A[i]不匹配,求距离,再加A串 i − 1 i-1 i−1前与B串 j j j前的数相匹配的最优值再加k
t h i r d third third:
B[j]不匹配,求距离,再加A串 i i i前与B串 j − 1 j-1 j−1前的数相匹配的最优值再加k
则转移方程为: f [ i ] [ j ] = m i n ( f [ i − 1 ] [ j − 1 ] , f [ i − 1 ] [ j ] + k , f [ i ] [ j − 1 ] + k ) f[i][j]=min~(~f[i-1][j-1],f[i-1][j]+k,f[i][j-1]+k~) f[i][j]=min ( f[i−1][j−1],f[i−1][j]+k,f[i][j−1]+k )
再处理一下边界: f [ i ] [ 0 ] = k ∗ i , f [ 0 ] [ j ] = k ∗ j f[i][0]=k*i,f[0][j]=k*j f[i][0]=k∗i,f[0][j]=k∗j
也就是,当A1–>i与B1匹配时,A1–>i-1都会与空格匹配…………
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned long long
using namespace std;
const LL N=1e6+100,M=2010;
string s1,s2;
LL m,a[N],b[N],f[M][M];
int main ( )
{
freopen ( "blast.in","r",stdin );
freopen ( "blast.out","w",stdout );
cin >>s1>>s2>>m;
LL len1=s1.size ( ),len2=s2.size ( );
for ( int i=1;i<=len1;i++ ) a[i]=s1[i-1],f[i][0]=m*i; //边界
for ( int i=1;i<=len2;i++ ) b[i]=s2[i-1],f[0][i]=m*i;
for ( int i=1;i<=len1;i++ ) for ( int j=1;j<=len2;j++ ) f[i][j]=min ( f[i-1][j-1]+abs ( a[i]-b[j] ),min ( f[i][j-1],f[i-1][j] )+m );
printf ( "%d",f[len1][len2] );
return 0;
}
四、村庄重建
【问题描述】 B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路
造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法
通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重
建完成的村庄。
给出 B 地区的村庄数 N,村庄编号从 0 到 N-1,和所有 M 条公路的长度,公
路是双向的。并给出第 i 个村庄重建完成的时间 t[i],你可以认为是同时开始
重建并在第 t[i]天重建完成,并且在当天即可通车。若 t[i]为 0 则说明地震未
对此地区造成损坏,一开始就可以通车。之后有 Q 个询问(x, y, t),对于每个
询问你要回答在第 t 天,从村庄 x 到村庄 y 的最短路径长度为多少。如果无法找
到从 x 村庄到 y 村庄的路径,经过若干个已重建完成的村庄,或者村庄 x 或村庄
y 在第 t 天仍未重建完成 ,则需要返回-1。 【数据输入】
输入文件 rebuild.in 的第一行包含两个正整数 N,M,表示了村庄的数目与
公路的条数。
第二行包含 N 个非负整数 t[0], t[1], „, t[N – 1],表示了每个村庄重建完
成的时间,数据保证了 t[0] ≤ t[1] ≤ „ ≤ t[N – 1]。
接下来 M 行,每行 3 个非负整数 i, j, w,w 为不超过 10000 的正整数,表
示了有一条连接村庄 i 与村庄 j 的道路,长度为 w,保证 i≠j,且对于任意一对
村庄只会存在一条道路。
接下来一行也就是 M+3 行包含一个正整数 Q,表示 Q 个询问。
接下来 Q 行,每行 3 个非负整数 x, y, t,询问在第 t 天,从村庄 x 到村庄 y 的
最短路径长度为多少,数据保证了 t 是不下降的。
【数据输出】
输出文件 rebuild.out 包含 Q 行,对每一个询问(x, y, t)输出对应的答案,
即在第 t 天,从村庄 x 到村庄 y 的最短路径长度为多少。如果在第 t 天无法找到
从 x 村庄到 y 村庄的路径,经过若干个已重建完成的村庄,或者村庄 x 或村庄 y
在第 t 天仍未修复完成,则输出-1。
【输入输出样例】 rebuid.in
4 5
1 2 3 4
0 2 1
2 3 1
3 1 2
2 1 4
0 3 5
4
2 0 2
0 1 2
0 1 3
0 1 4
rebuid.out
-1
-1
5
4
【数据说明】
对于 30%的数据,有 N≤50; - 5 -
对于 30%的数据,有 t[i] = 0,其中有 20%的数据有 t[i] = 0 且 N>50;
对于 50%的数据,有 Q≤100;
对于 100%的数据,有 N≤200,M≤N*(N-1)/2,Q≤50000,所有输入数据涉及整
数均不超过 100000。
思路:Floyd+离线
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned long long
using namespace std;
const LL N=1e6+100,M=2010;
LL x,y,u,v,w,n,m,k,wz,a[M],t[N],f[M][M];
void floyd ( LL k )
{
for ( int i=0;i<n;i++) for ( int j=0;j<n;j++) f[i][j]=min ( f[i][j],f[i][k]+f[k][j] );
}
void zdl ( LL time )
{
for ( int i=wz;i<n;i++ )
{
if ( a[i]<=time ) floyd ( i ),wz=i;
else { wz=i;return; }
}
}
int main ( )
{
// freopen ( "rebuild.in","r",stdin );
// freopen ( "rebuild.out","w",stdout );
memset ( f,0x3f,sizeof ( f ) );
scanf ( "%lld %lld",&n,&m );
for ( int i=0;i<n;i++ ) scanf ( "%lld",&a[i] );
for ( int i=1;i<=m;i++ ) scanf ( "%lld %lld %lld",&u,&v,&w ),f[u][v]=f[v][u]=w;
// for ( int i=1;i<=n;i++ )
// {
// for ( int j=1;j<=m;j++ ) printf ( "%d ",f[i][j] );
// printf ( "\n" );
// }
scanf ( "%lld",&k );
for ( int i=1;i<=k;i++ )
{
scanf ( "%lld %lld %lld",&x,&y,&t[i] );
zdl ( t[i] );
if ( a[x]<=t[i] && a[y]<=t[i] && f[x][y]!=0x3f3f3f3f ) printf ( "%lld\n",f[x][y] );
else printf ( "-1\n" );
}
return 0;
}