作物杂交(蓝桥最短路):bfs优先队列(矩阵/链式前向星)/dfs

该题和普通最短路的区别,多了一个中间值。即不是直接u->v,而是u,t->v

bfs从前往后(s->t)

优先队列+矩阵 

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e3+5;
const int inf=0x3f3f3f3f;
int n,m,k,t,a[maxn],dis[maxn],vis[maxn],g[maxn][maxn],x,y,c;
struct nn{
    int v,t;
    friend bool operator < (nn a,nn b){
        return a.t>b.t;
    }
}; 
priority_queue<nn> q;
void bfs(){
    nn cur,tem;
    while(!vis[t]){     
        cur=q.top();
        q.pop();
        int u=cur.v;
        if(!vis[u]){//push在q里的,是用已有的可以合成的,但还没合成 
	        vis[u]=1;
			//这一步才合成了u,改变vis。才能使其它的可以合成,用for来找 
	        for(int i=1;i<=n;i++){
	        	if(g[u][i]!=inf){//有路 
	        		int v=g[u][i];
	        		if(!vis[v]&&vis[i]){//没有合成过v才进去,剪枝 
		                int tt=dis[u]+max(a[u],a[i]);
		                if(tt<dis[v]){
		                    dis[v]=tt;
		                    q.push({v,tt}); 
							//已有的材料可以合成的push 
		                }
		            }
				}
	        }	
		}
        
    }
    return ;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&t);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        dis[i]=inf;vis[i]=0;
        for(int j=1;j<=n;j++){
            g[i][j]=inf;
        }            
    }    
    for(int i=0;i<m;i++){
        scanf("%d",&x);
//        q.push({x,0});不用放入,没意义 
        vis[x]=1;dis[x]=0;
    }    
    for(int i=0;i<k;i++){
        scanf("%d%d%d",&x,&y,&c);
        g[x][y]=g[y][x]=c;
        int tt=max(a[x],a[y]);
        if(vis[x]&&vis[y]&&tt+dis[x]<dis[c]){
            dis[c]=tt+dis[x];
            q.push({c,dis[c]}); 
        }            
    }
    bfs();
    cout<<dis[t]<<endl;
    return 0;
}

优先队列+链式前向星 

#include <bits/stdc++.h>
using namespace std;
const int maxn=2020;
const int maxm=2e5+10;
const int inf=0x3f3f3f3f;
int n,m,k,key,x,y,z,cnt=0;
int a[maxn],dis[maxn],vis[maxn],head[maxn];
int e[maxm],to[maxm],cost[maxm],nex[maxm];
void creat(int u,int v,int t,int c){
    e[++cnt]=v;//经过的点 
    to[cnt]=t;//到达的点 
    cost[cnt]=c;
    nex[cnt]=head[u];
    head[u]=cnt;
}
struct nn{
    int v,tt;
    friend bool operator < (nn a,nn b){
        return a.tt>b.tt;//小顶堆,用>
    }
}; 
priority_queue<nn> q;
void bfs(){
    nn cur,tem;
    while(!q.empty()){    
        cur=q.top();
        q.pop();
        int u=cur.v;        
        if(!vis[u]){
            vis[u]=1;
            //已有的才能合成 
            for(int i=head[u];i;i=nex[i]){
                int v=e[i],t=to[i],c=cost[i];
                if(!vis[t]&&vis[v]){
                    int tt=dis[u]+c;
                    if(tt<dis[t]){
                        dis[t]=tt;
                        q.push({t,tt});    
                    }
                }
            }
        }
    }
    return ;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&key);
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        dis[i]=inf;        
    }    
    for(int i=0;i<m;i++){
        scanf("%d",&x);
//        q.push({x,0}); 不用放入,没意义 
        vis[x]=1;
        dis[x]=0;
    }    
    for(int i=0;i<k;i++){
        scanf("%d%d%d",&x,&y,&z);
        int tt=max(a[x],a[y]);
        if(vis[x]&&vis[y]&&tt+dis[x]<dis[z]){
            dis[z]=tt+dis[x];
            q.push({z,dis[z]}); 
        }
        creat(x,y,z,tt);
        creat(y,x,z,tt);        
    }
    bfs();//最短路,bfs是void 
    cout<<dis[key]<<endl;//输出直接看dis[target] 
    return 0;
}

dfs 从后往前

#include<bits/stdc++.h>
using namespace std;
const int maxn=2010;
int n,m,k,mb,a[maxn],vis[maxn];//vis记录该点是否已合成 
struct node{
	int num;//记录有几种合成方法 
	int u[maxn],v[maxn];
	int mint;//合成该点 用的最短时间 
}fa[maxn];
//dfs就是从结尾往前找。 
int dfs(int x){//可以返回x能否被合成
	if(!fa[x].num) return 0;//=0表示没有可以合成x的 
	for(int i=1;i<=fa[x].num;i++){
		int u=fa[x].u[i],v=fa[x].v[i];
		//如果uv中有一个没出现过,dfs看看能否合成。当俩都出现过才能合成x 
		if(!vis[u]) 
			if(!dfs(u))continue;
		if(!vis[v])	
			if(!dfs(v))continue; 	
		//这俩要都生成了,才能合成x ,取max满足俩都生成 
		int tt=max(fa[u].mint,fa[v].mint)+max(a[u],a[v]);
		if(!fa[x].mint) fa[x].mint=tt;//mint==0表示x还没合成过。初始化都为0  
		else fa[x].mint=min(fa[x].mint,tt);
	} 
	vis[x]=1;//一旦dfs到底发现不能合成return0.所以没返回0的就是能合成的 
	return 1; 
}
int main(){
	int x,y,z;
	scanf("%d%d%d%d",&n,&m,&k,&mb);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		vis[i]=0;
	}
	for(int i=1;i<=m;i++){
		scanf("%d",&x);
		vis[x]=1;
	}
	for(int i=1;i<=k;i++){
		scanf("%d%d%d",&x,&y,&z);
		int tem=++fa[z].num;
		fa[z].u[tem]=x;
		fa[z].v[tem]=y;		
	}
	dfs(mb);
	cout<<fa[mb].mint<<endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_50904510/article/details/121257370