好题分析---最短Hamilton路径+枚举优化

本文探讨了如何使用动态规划解决路径规划问题,通过枚举所有可能的路径并确保不重不漏,以找到最短距离。在给定的示例中,通过二进制表示路径并迭代更新状态,最终找到到达终点的最短路径。同时,文章还介绍了一种优化的枚举方法,用于字符串匹配,通过记录字符的下一个出现位置,提高查询效率。
摘要由CSDN通过智能技术生成

++

 弄懂代码很容易,但是问题的关键是----为什么可以这么做??----对于状态的划分和转移,最关键的一点就是----不重不漏,对于确定的终点,我们应该要怎么设计方程呢?也就是说,要如何高效地枚举所有经过节点,并到达终点的情况。

假设:一共有七个点,用0,1,2,3,4,5,6来表示,那么先假设终点就是5,在这里我们再假设还没有走到5这个点,且走到的终点是4,那么有以下六种情况:
first: 0–>1–>2–>3–>4 距离:21
second: 0–>1–>3–>2–>4 距离:23
third: 0–>2–>1–>3–>4 距离:17
fourth: 0–>2–>3–>1–>4 距离:20
fifth: 0–>3–>1–>2–>4 距离:15
sixth: 0–>3–>2–>1–>4 距离:18

同理:假设还没有走到5这个点儿,且走到的终点是3,那么有一下六种情况:
first: 0–>1–>2–>4–>3 距离:27
second: 0–>1–>4–>2–>3 距离:22
third: 0–>2–>1–>4–>3 距离:19
fourth: 0–>2–>4–>1–>3 距离:24
fifth: 0–>4–>1–>2–>3 距离:26
sixth: 0–>4–>2–>1–>3 距离:17

那么由于4-5,3-5的距离是个定值,就可以以此来确定到达5的最短距离。因此,我们不妨可以这样枚举------确定一个终点,枚举所有点到该终点的距离,并取最小值来更新答案。

 .DP分析:
用二进制来表示要走的所以情况的路径,这里用i来代替
例如走0,1,2,4这三个点,则表示为:10111;
走0,2,3这三个点:1101;

QQ浏览器截图20200816153106.png

#include<iostream>
#include<cstring>
using namespace std;
const int M=1<<20;
int n;
int w[21][21];
int f[M][21];
int a,b;


int main()
{
    
    
    cin>>n;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
          cin>>w[i][j];
        }
    }

    //对状态进行枚举,接着在每个状态下枚举所有终点的情况,对于终点来说,在对应的点,枚举可以由点k迁移而来的点。
    memset(f,0x3f3f3f,sizeof f);
    f[1][0]=0;
    for(int i=0;i<1<<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i>>j&1)    //表示这种情况至少要包含j。
             {
                for(int k=0;k<n;k++)
                {
                    if((i-(1<<j))>>k&1)    //去掉j的所有路径是否包含k
                    {
                        f[i][j]=min(f[i-(1<<j)][k]+w[k][j],f[i][j]);
                    }
                }
             }
        }
    }
    
    
    cout<<f[(1<<n)-1][n-1];

    
    return 0;
}

(2) 

 本题采用优化枚举,用空间换时间,从后往前遍历,依次记录当前位置的字符对应的下一个(a——z)在什么位置,没有的话就置为-1,紧接着查询即可。


#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+5;
char a[maxn],b[maxn];
int t,last[30],nxt[maxn][30];
void init(){
        memset(last,-1,sizeof last);
    	int d=strlen(a+1);
        for(int i=d;i>=1;i--)
        {
           for(int j=1;j<=26;j++)
               nxt[i][j]=last[j];
             last[a[i]-'a'+1]=i;
        }
       
}
bool check(){

    int la=strlen(a+1);
    int lb=strlen(b+1);
    int i=last[b[1]-'a'+1];
    if(i==-1) return 0;
    for(int j=2;j<=lb;j++)
    {
        i=nxt[i][b[j]-'a'+1];
        if(i==-1) return 0;
    }
    
    return 1;
}
int main(){
	scanf("%s",a+1);
	init();
	scanf("%d",&t);
	while(t--){
		scanf("%s",b+1);
		if(check()){
			printf("Yes\n");
		}else{
			printf("No\n");
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值