zoukankan      html  css  js  c++  java
  • 【K短路】牛慢跑

    牛慢跑

    据说是(k)短路模板,要用(A^*),然而我不会。我是用拓扑排序加堆优化广搜水过去的。第一道完全靠自己做出来的紫题,调了两个小时,交了两遍。果然我还是太菜了。

    正解的话,可以看红太阳的博客

    题面

    给出(n)个点(m)条边的有向无环图,求从(n)(1)的前(k)条最短路的值。

    (1≤N≤1000 ,1 <= M <= 10000 ,1≤K≤100)

    输入格式

    (1)行:三个以空格分隔的整数:(N,M)(K).

    (2..M + 1)行:第(i + 1)行描述了使用三个以空格分隔的整数的下坡牛路径:(X_i,Y_i)和$D_i(1≤Di≤1000000) $

    输出格式

    (1..K):行(i)包含第(i)个最短路径的长度,如果不存在这样的路径,则为(-1)。如果多次出现最短路径长度,请务必在输出中多次列出。

    输入样例

    5 8 7 
    5 4 1 
    5 3 1 
    5 2 1 
    5 1 1 
    4 3 4 
    3 1 1 
    3 2 1 
    2 1 1 
    

    输出样例

    1 
    2 
    2 
    3 
    6 
    7 
    -1 
    

    拓扑排序加堆优化广搜

    以下是我的神奇做法。

    要找前(k)条最短路,怎么找?我观察了一下样例的图,发现每个点的路径长度会被更新很多次,但都是由直接指向他的点更新来的(废话),也就是说,他前面的点怎样更新的我不关心,我只关心这个点前(k)条最短路的长度。

    那直接用堆存一下就好了。

    但是我们要保证他前面的点已经更新完了。前面说了这是一个有向无环图,自然想到拓扑排序。

    但我之前犯了一个错误,它花费了我一个多小时的时间。这个题要求必须从(n)号点出发,但是有些点(n)号点到不了,它们一开始入度就为零。如果不把这些点的影响去掉,后面就会出错。果然我菜鸡的本质难以掩盖。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    long long read(){
    	long long x=0;int f=0;char c=getchar();
    	while(c<'0'||c>'9')f|=c=='-',c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return f?-x:x;
    }
    
    int n,m,k;
    struct Dier{//前向星
    	int to,next,w;
    }a[10004];
    int head[1001],cnt;
    void add(int x,int y,int z){//单向边
    	a[++cnt].to=y,a[cnt].next=head[x],a[cnt].w=z,head[x]=cnt;
    }
    
    priority_queue<int,vector<int>,greater<int> >q[1005];//小根堆
    int in[1001],Q[1001],h,t;
    //  入度     队列
    
    int main(){
    	n=read(),m=read(),k=read();
    	for(int i=1,x,y,z;i<=m;++i){
    		x=read(),y=read(),z=read();
    		add(x,y,z),in[y]++;
    	}
        
        //拓扑
    	for(int i=n;i;--i)
    		if(!in[i]) Q[++t]=i;
    	for(int i=1;i<=t;++i){
    		if(Q[i]==n) continue;//n号点的影响不应该去掉
    		int u=Q[i];
    		for(int i=head[u],v;v=a[i].to,i;i=a[i].next){
    			in[v]--;
    			if(!in[v]) Q[++t]=v;//斩草不除根,后面麻烦无穷
                //只要不是从n号点直接或间接转移过来的入度都要去掉,因为他们会妨碍我们后面的入队
    		}
    	}
        
    	t=1,Q[1]=n;//初始化一下
    	q[n].push(0);
    	while(h<t){//广搜
    		int u=Q[++h],ls=0;
    		while(u!=1&&!q[u].empty()&&++ls<=k){//只取前k条就好
              //保证1号点的距离不会被pop掉
    			for(int i=head[u],v;v=a[i].to,i;i=a[i].next)
    				q[v].push(q[u].top()+a[i].w);//更新距离
    			q[u].pop();
    		}
            //计算入度一定要独立出来,不能和更新距离放在一起,因为那样会导致入度被减很多次
    		for(int i=head[u],v;v=a[i].to,i;i=a[i].next){
    			in[v]--;
    			if(!in[v]) Q[++t]=v;
    		}
    	}
    	while(!q[1].empty()&&k){//输出答案
    		printf("%d
    ",q[1].top()),q[1].pop(),k--;
    	}
    	for(int i=1;i<=k;++i) printf("-1
    ");//有可能并没有k条路可以走
    	return 0;
    }
    

    欢迎指正评论O(∩_∩)O~~

  • 相关阅读:
    最大回文子串
    找出不含重复字符的最长子串的长度
    链表表示的2个数相加
    如何胜任一个小型公司的技术总监?我的感想
    React 的坑
    MobX 学习
    摘要
    AI 帮助涂鸦
    计算机的前世今生
    常用编辑器实用技巧(pycharm、sublimeText、vim、vscode、Jupyter)
  • 原文地址:https://www.cnblogs.com/kylinbalck/p/9888219.html
Copyright © 2011-2022 走看看