zoukankan      html  css  js  c++  java
  • $P2453 [SDOI2006] $最短距离

    #$Description$ [题面](https://www.luogu.org/problem/P2453) 题面比较复杂,大概就是有几个操作函数要求将起始字符串变换为目标字符串,每个操作有代价,求代价最小值 #$Solution$ 其实很多状态压缩类动态规划可以转换成最短路问题,只需要将状态压缩为一个点就行,一般处理变换操作可以使用这种方法。

    实际上最短路问题就是在图上跑(DP),但由于(DP)转移受顺序限制需要在拓扑序上跑,而(dijkstra)只需要指定从起点到终点就行。

    在这类题中,我们建出来的图就是一个状态转移图,而一般的状压(DP)就是在图上跑(DP),和(dijkstra)是等效的。

    对于这个题,关键点在于如何设计状态和连边建图

    (Solution)

    这道题有一个比较显然的性质:就对于最优变换方案,每个时刻目标串一定是最终串的前缀,源串一定是起始串的后缀。

    证明:假设当前目标串不是最终串的前缀,那么有两种可能:
    (1.)长度超过最终串:那就必须删除,这和在插入前删除是等效的
    (2.)目标串有字符不匹配最终串,那么之后还需要(delete)或者按之前的路修改回去,不如提前就修改或者直接(delete)

    有了这个性质,状态就比较好表示了,只有((lena+1) imes(lenb+1))种状态

    Me0ip4.png

    状态计算函数就是这个

    int id(int x,int y)//x是目标串长度,y是源串长度 
    {
    	return x*(lena+1)+y+1;
    }
    

    考虑如何连边

    操作一、二、四是比较显然的,操作三要注意判断一下,相同才能连边,操作五同理,对于操作清空要特别注意,如果你直接(id(i,j)->id(i,0))是错误的,假设(j)(0),那么根据题面就可以不断删除,而代价是(-1),所以要特别判断这个情况

    void link()
    {
    	for(re int i=0;i<=lenb;++i)
    	 for(re int j=0;j<=lena;++j)
    	 {
    	 	if(j>=1) add(id(i,j),id(i,j-1),w[1]);//del
    	 	if(j>=1&&i<lenb)
    	 	{
    	 		add(id(i,j),id(i+1,j-1),w[2]);//replace任何情况都行 
    	 		if(B[i+1]==A[lena-j+1]) add(id(i,j),id(i+1,j-1),w[3]);//相等则可以直接copy 
    		}
    		if(i<lenb)
    		{
    			add(id(i,j),id(i+1,j),w[4]);
    		}
    		if(j>=2&&i<=lenb-2)
    		{
    			if(B[i+1]==A[lena-j+2]&&B[i+2]==A[lena-j+1])
    			add(id(i,j),id(i+2,j-2),w[5]);//判断 
    		}
    		if(i==lenb&&j!=0)//这里一定要注意 
    		{
    			add(id(i,j),id(i,0),j*w[1]-1);
    		}
    	 }
    }
    

    然后加个(dijkstra)(id(0,lena))跑到(id(lenb,0))即可

    完整代码

    (Code)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define re register
    #define maxn 200010
    #define INF 0x3f3f3f3f
    using namespace std;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    struct Edge{
    	int v,w,nxt;
    }e[maxn<<2];
    int w[101],cnt,head[maxn],vis[maxn];
    char A[220],B[220];
    int lena,lenb,T,S,dis[maxn];
    int id(int x,int y)//x是目标串长度,y是源串长度 
    {
    	return x*(lena+1)+y+1;
    }
    inline void add(int u,int v,int w)
    {
    	e[++cnt].v=v;
    	e[cnt].w=w;
    	e[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    struct node{
    	int u,d;
    	bool operator <(const node&rhs) const{
    		return rhs.d<d;
    	}
    };
    priority_queue<node> q;
    void dijkstra(int s)
    {
    	while(!q.empty()) q.pop();
    	q.push((node){s,0});
    	memset(dis,INF,sizeof(dis));
    	dis[s]=0;
    	while(!q.empty())
    	{
    		node now=q.top();
    		q.pop();
    		if(vis[now.u]) continue;
    		vis[now.u]=1;
    		for(int i=head[now.u];i;i=e[i].nxt)
    		{
    			int ev=e[i].v;
    			if(dis[ev]>dis[now.u]+e[i].w)
    			{
    				dis[ev]=dis[now.u]+e[i].w;
    				q.push((node){ev,dis[ev]});
    			}
    		}
    	}
    }
    void link()
    {
    	for(re int i=0;i<=lenb;++i)
    	 for(re int j=0;j<=lena;++j)
    	 {
    	 	if(j>=1) add(id(i,j),id(i,j-1),w[1]);//del
    	 	if(j>=1&&i<lenb)
    	 	{
    	 		add(id(i,j),id(i+1,j-1),w[2]);//replace任何情况都行 
    	 		if(B[i+1]==A[lena-j+1]) add(id(i,j),id(i+1,j-1),w[3]);//相等则可以直接copy 
    		}
    		if(i<lenb)
    		{
    			add(id(i,j),id(i+1,j),w[4]);
    		}
    		if(j>=2&&i<=lenb-2)
    		{
    			if(B[i+1]==A[lena-j+2]&&B[i+2]==A[lena-j+1])
    			add(id(i,j),id(i+2,j-2),w[5]);//判断 
    		}
    		if(i==lenb&&j!=0)//这里一定要注意 
    		{
    			add(id(i,j),id(i,0),j*w[1]-1);
    		}
    	 }
    }
    
    int main()
    {
        cin>>A+1,lena=strlen(A+1);
        cin>>B+1,lenb=strlen(B+1);
        for(re int i=1;i<=5;++i) w[i]=read();
        S=id(0,lena);
        T=id(lenb,0);
        link();
        dijkstra(S);
        printf("%d
    ",dis[T]);
    	return 0;
    }
    
    
  • 相关阅读:
    For each db / table
    转---网络上来的,做一个数组样的结构
    JAVA 相关资料
    转--也不知是哪位大侠写的了
    T-SQL切割字符串方法小结 2
    OPENQUERY
    行集函数专题
    行列转换
    第一章 SQL基础
    解释型语言与编译型语言的区别
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/11824466.html
Copyright © 2011-2022 走看看