2016_特长生

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 i1前与B串 j j j前的数相匹配的最优值再加k

t h i r d third third

B[j]不匹配,求距离,再加A串 i i i前与B串 j − 1 j-1 j1前的数相匹配的最优值再加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[i1][j1]f[i1][j]+k,f[i][j1]+k )

再处理一下边界: f [ i ] [ 0 ] = k ∗ i , f [ 0 ] [ j ] = k ∗ j f[i][0]=k*i,f[0][j]=k*j f[i][0]=ki,f[0][j]=kj

也就是,当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;
}

总结:以后1,2题,全部都检查两遍!!!

3,4题尽量拿分,dp一会儿写不出来就改用dfs!!!

一二题千万别错……!!!……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值