zoukankan      html  css  js  c++  java
  • 【图论】AcWing 342. 道路与航线 题目解答 (拓扑序+dijkstra)

    传送门:https://www.acwing.com/problem/content/344/

    吐槽:这就是一道大膜你模拟啊。
    不得不说写作课的时候想题大有启发(雾

    分析

    看到这题有负权,想到用SPFA,可惜这题范围很大,完全被卡死了(然而有人用SPFA优化过了),故考虑别的做法。
    大致思路:
    道路联通的部分看成,那么航线则是通过有向边将每个块连起来的,故从整体上看,有向边和各个块组成了一个图。
    在处理块的时候,可以在输入道路的时候建立,方法类似于对图进行染色。

    而根据题意,这个图是DAG(有向无环图),可以考虑用拓扑序处理。
    首先我们可以对这个DAG进行从源点所在块一遍深搜,然后将源点能够到达的其他块打上标记。

    接下来我们只需对源点所在块以及它能够到达的其他块进行讨论就行了。(其他块不需要管)

    类似于拓扑序的做法,
    在处理航线的时候,维护一下入度。
    然后我们先将源点所在块入队,将块中点全部丢进优先队列里面进行 dijkstra,如果dijktra过程中访问到了

    • 不是本块里面的点,需要对入度进行维护,当一个块(不是当前块)入度为 (0) 时,将它丢进队列里面。
    • 是本块的点,像dijktra一样处理就好了~

    过程确实比较简单(大概),但是实现挺复杂的,建议自己先动手试试。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef pair<int,int> PII;
    const int INF=0x3f3f3f3f;
    const int N=25005, M=5e4+5;
    int n,p,r,s;
    int in[N];
    int col,id[N];
    vector<int> block[N];
    bool tag[N];
    bool vis[N];
    int d[N];
    queue<int> q; // for topo block
    priority_queue<PII,vector<PII>,greater<PII> > que; // for dijk()
    
    struct Store{
    	int u,v,w;
    }store[M<<1];
    
    struct node{
    	int next,to,w;
    }e[M<<1],ee[M<<1];
    
    int cnt,h[N];
    void addd(int u,int v){ee[cnt].to=v;ee[cnt].next=h[u];h[u]=cnt++;}
    
    int head[N],tot;
    void add(int u,int v,int w){e[tot].to=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;}
    
    void assign(int u){
    	id[u]=col;
    	block[col].push_back(u);
    	for(int i=head[u];~i;i=e[i].next){
    		int go=e[i].to;
    		if(id[go]!=0) continue;
    		assign(go);
    	}
    }
    
    void dfs(int u){
    	tag[u]=true;
    	for(int i=h[u];~i;i=ee[i].next){
    		int go=ee[i].to;
    		//cerr<<go<<' ';
    		if(tag[go]) continue;
    		dfs(go);
    	}
    }
    
    void dijk(int color){
    	while(que.size()){
    		auto hd=que.top(); que.pop();
    		
    		int ver=hd.second;
    		if(vis[ver]) continue;
    		vis[ver]=true;
    		
    		for(int i=head[ver];~i;i=e[i].next){
    			int go=e[i].to;
    			if(id[go]!=color) in[id[go]]--;
    			if(!in[id[go]] && id[go]!=color) q.push(id[go]);
    			
    			if(d[go]>d[ver]+e[i].w){
    				d[go]=d[ver]+e[i].w;
    				if(id[go]==color) que.push({d[go],go});			
    			}
    		}
    	}
    }
    
    void topo(){
    	//for(int i=1;i<=col;i++) cerr<<in[id[i]];
    	in[id[s]]=0;
    	q.push(id[s]);
    	
    	while(q.size()){
    		int pt=q.front(); q.pop();
    		cerr<<pt<<' ';
    		for(auto i:block[pt]) que.push({d[i],i});
    		dijk(pt);
    	}
    }
    
    int main(){
    	memset(head,-1,sizeof head);
    	memset(h,-1,sizeof h);
    	
    	cin>>n>>p>>r>>s;
    	memset(d,0x3f,sizeof d);
    	d[s]=0;
    	
    	while(p--){
    		int u,v,w; cin>>u>>v>>w;
    		add(u,v,w); add(v,u,w);
    	}	
    	
    	for(int i=1;i<=n;i++)
    		if(!id[i]) {
    			col++;
    			assign(i);
    		}
    	
    	for(int i=1;i<=r;i++){
    		int u,v,w;
    		cin>>u>>v>>w;
    		store[i]={u,v,w};
    		addd(id[u],id[v]);
    		//cerr<<id[u]<<' '<<id[v]<<endl;
    	}
    	
    	dfs(id[s]);
    	
    	for(int i=1;i<=r;i++){
    		int u=store[i].u, v=store[i].v, w=store[i].w;
    		if(!tag[id[u]]) continue;
    		//cerr<<"imsb";
    		add(u,v,w);
    		in[id[v]]++;
    	}
    	
    	topo();
    	
    	for(int i=1;i<=n;i++)
    		if(d[i]==INF) puts("NO PATH");
    		else cout<<d[i]<<endl;
    		
    	return 0;
    }
    

    彩蛋

  • 相关阅读:
    判断输入的是否是汉字(中文,不包括中文符号)
    第XX行将截断字符串或二进制数据。语句已终止
    Joomla学习之旅开始啦
    bean加载与注入之重新理解 L
    Excelsior JET 7.6 MP5 发布
    Squid Analyzer 5.1 发布,Squid日志统计
    flashrd 1.3 发布,OpenBSD 安装器
    Oracle 宣布 MySQL 5.6 正式版发布
    Spring Hateoas 0.4 发布
    MacPorts 2.1.3 发布,Mac 软件包管理
  • 原文地址:https://www.cnblogs.com/Tenshi/p/14508494.html
Copyright © 2011-2022 走看看