zoukankan      html  css  js  c++  java
  • CCF CSP 201712-4 行车路线

    思路:

    这题有两种思路:DijkstraSPFA,都可以100分;在求最短路径时,Dijkstra往往是效率比较高的解法,但是本题使用Dijkstra的变形并不能完全贴合题意,因为这种贪心算法遇到“局部最优≠整体最优”的情况就失效了,但是不妨拿来练练手hh;

    Dijkstra:
    大体框架还是照搬Dijkstra,但是注意使用long long,唯一变形的就是另设一个数组clen[],用来表示第i个结点当前是一段长为clen[i]的短路的终点,因此在下一条长为L的短路接着这条短路时,就可以先减去clen[i]的平方,再加上clen[i]+L的平方了;

    SPFA:
    1.将大路和小路的路径分开存储,首先利用Ford算法的思想,将小路的距离数组dis_1[i][j]全部更新为走小路的情况下,ij的最短路径;
    2.然后利用spfa算法的思想(其实和BFS差不多),当前路口为now,下一个路口i我们可以从2遍历到n,分三种情况前进:(1)从小路到now,现在走大路从nowi;(2)从大路到now,现在走大路从nowi;(3)从大路到now,现在走小路从nowi
    3.最后输出min(d_0[n],d_1[n])即可;

    Dijkstra代码:

    #include<bits/stdc++.h>
    #define p_b(a) push_back(a)
    typedef long long LL; 
    using namespace std;
    const int MAX_N=505;
    const LL INF=LLONG_MAX-100;
    vector<int> node[MAX_N];
    LL dis[MAX_N][MAX_N];//两个结点之间的距离 
    bool type[MAX_N][MAX_N];//是否是小道 
    LL clen[MAX_N];//到点i时连续走的小路长
    LL d[MAX_N];//点i的距离 
    bool known[MAX_N]={false,true};//点i是否已是最短路 
    int n,m;
    void dijkstra(){
    	fill(d+2,d+MAX_N,INF);
    	for(auto e:node[1]){ 
    		if(type[1][e]){
    			clen[e]=dis[1][e];
    			d[e]=clen[e]*clen[e];
    		}else d[e]=dis[1][e];
    	}
    	while(!known[n]){
    		int min_n;
    		LL min_d=INF;
    		for(int i=2;i<=n;i++){
    			if((!known[i])&&d[i]<min_d){
    				min_d=d[i];
    				min_n=i;
    			}
    		}
    		known[min_n]=true;
    		for(auto e:node[min_n]){
    			if(type[min_n][e]){
    				LL c=clen[min_n]+dis[min_n][e];
    				LL now=d[min_n]-clen[min_n]*clen[min_n]+c*c;
    				if(now<d[e]){
    					clen[e]=c;
    					d[e]=now;
    				}
    			}else{
    				LL now=d[min_n]+dis[min_n][e];
    				if(now<=d[e]){
    					clen[e]=0;
    					d[e]=now;
    				}
    			}
    		}
    	}		
    }
    int main(){
    	cin>>n>>m;
    	memset(dis,127,sizeof(dis));
    	for(int i=0;i<m;i++){
    		int t,a,b;
    		LL c;
    		cin>>t>>a>>b>>c;
    		node[a].p_b(b);
    		node[b].p_b(a);
    		if(c<dis[a][b]) dis[a][b]=dis[b][a]=c;
    		if(t) type[a][b]=type[b][a]=true; 
    	}
    	dijkstra();
    	cout<<d[n];
    	return 0;
    } 
    

    SPFA代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define rp(i,n) for(int i=0;i<n;i++)
    #define rpn(i,n) for(int i=1;i<=n;i++)
    #define mem(a,x) memset(a,x,sizeof(a))
    typedef long long LL;
    const int MAX_N=505;
    const LL INF=0x3f3f3f3f;
    int n,m;
    LL dis_0[MAX_N][MAX_N];//大路 
    LL dis_1[MAX_N][MAX_N];//小路
    LL d_0[MAX_N],d_1[MAX_N];//前驱分别为大路和小路时,结点i的最短路径 
    bool vst[MAX_N];//结点i是否在队列中 
    void ford(){//更新小路,使得dis_1[i][j]是从小路走的情况下i到j的最短距离 
    	for(int i=1;i<n;i++){
    		for(int j=i+1;j<=n;j++){
    			rpn(k,n) if(dis_1[i][k]<INF&&dis_1[k][j]<INF)
    				dis_1[i][j]=dis_1[j][i]=min(dis_1[i][j],dis_1[i][k]+dis_1[k][j]);
    		}
    	}				
    }
    int main(){	
    	cin>>n>>m;
    	mem(dis_0,INF),mem(dis_1,INF);
    	mem(d_0,INF),mem(d_1,INF);
    	d_0[1]=d_1[1]=0;
    	rp(i,m){
    		int t,a,b;
    		LL c;
    		cin>>t>>a>>b>>c;
    		if(t&&c<dis_1[a][b]) dis_1[a][b]=dis_1[b][a]=c;
    		else if(!t&&c<dis_0[a][b]) dis_0[a][b]=dis_0[b][a]=c;
    	}
    	ford();
    	queue<int> q;
    	q.push(1); 
    	while(!q.empty()){//spfa
    		int now=q.front();
    		q.pop();
    		vst[now]=false;
    		for(int i=2;i<=n;i++){//从now走到i 
    			bool update=false;
    			if(dis_0[now][i]<INF){
    				LL d=d_0[now]+dis_0[now][i];//之前走大路,现在还是从大路走到i 
    				if(d<d_0[i]){
    					d_0[i]=d;
    					update=true;
    				}
    				d=d_1[now]+dis_0[now][i];//之前走小路,现在走大路 
    				if(d<d_0[i]){
    					d_0[i]=d;
    					update=true;
    				}
    			}		
    			if(dis_1[now][i]<INF){
    				LL d=d_0[now]+dis_1[now][i]*dis_1[now][i];//之前走大路,现在从小路走到i
    				if(d<d_1[i]){
    					d_1[i]=d;
    					update=true;
    				} 
    			}
    			if(update&&!vst[i]){
    				q.push(i);
    				vst[i]=true;
    			}
    		}
    	}
    	cout<<min(d_0[n],d_1[n]);
    	return 0;
    }
    
  • 相关阅读:
    vision transformer
    亮剑,gacutil.exe
    MOSS自定义登陆页面
    查看应用程序的进程ID
    基于AD的表单认证 Moss2010
    js 实现拖动
    获取指定数据库表, 以及指定表的数据信息
    二分法
    JZ053表示数值的字符串
    JZ054字符流中第一个不重复的字符
  • 原文地址:https://www.cnblogs.com/yuhan-blog/p/12308880.html
Copyright © 2011-2022 走看看