zoukankan      html  css  js  c++  java
  • Codeforces 576D. Flights for Regular Customers 题解

    题目链接:D. Flights for Regular Customers

    题目大意:给定一个(n)个点(m)条边的有向图,第(i)条边只有再你之前经过了(d_i)条边之后才可以通过,求从(1)点到(n)号点的最短距离。


    题解:因为边的(d_i)限制很麻烦,所以先考虑除掉这个限制,可以将所有边按照(d_i)排序后依次加入到原图中去,这样就去掉了这个限制。

    那么处理答案可以先找出所有用(d_i)步可以到达的点,然后对整张图跑一边 bfs 求出最小的答案。

    那么怎么找出(d_i)步可以到达的点的个数呢?可以将边集用邻接矩阵来处理,然后跑一遍矩阵快速幂即可。好了,这一题做完了。

    算一下时间复杂度是(O(n^3m ext{log}d))的,这个数据范围虽然小,不过应该过不掉(如果卡常过掉的请受我一拜),可是这个算法怎么优化呢?似乎没有办法优化了,这是我们想起一句极为经典话:“智商不够,压位来凑。”注意到转移矩阵只有(01)两个值,所以可以用 bitset 来优化,那么邻接矩阵就需要反过来,即原来(u-->v)的边要反向变为(v-->u)的边,否则再快速幂时很难优化。时间复杂度为(O(frac{n^3m ext{log}d}{omega}))

    下面是代码:

    #include <queue>
    #include <bitset>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int Maxn=150;
    const int Maxm=150;
    const int Inf=0x3f3f3f3f;
    int n,m;
    struct Edge{
    	int u,v;
    	int d;
    	friend bool operator <(Edge p,Edge q){
    		return p.d<q.d;
    	}
    }edge[Maxm+5];
    int dis[Maxn+5];
    struct Matrix{
    	bitset<Maxn+5> a[Maxn+5];
    	friend bitset<Maxn+5> operator *(bitset<Maxn+5> a,Matrix b){
    		bitset<Maxn+5> ans;
    		for(int i=0;i<n;i++){
    			ans[i]=(a&b.a[i]).any();
    		}
    		return ans;
    	}
    	friend Matrix operator *(Matrix a,Matrix b){
    		Matrix ans;
    		for(int i=0;i<n;i++){
    			for(int j=0;j<n;j++){
    				if(a.a[i][j]){
    					ans.a[i]=ans.a[i]|b.a[j];
    				}
    			}
    		}
    		return ans;
    	}
    }a;
    void quick_power(Matrix a,int b,bitset<Maxn+5> &ans){
    	while(b){
    		if(b&1){
    			ans=ans*a;
    		}
    		a=a*a;
    		b>>=1;
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].d);
    		edge[i].u--;
    		edge[i].v--;
    	}
    	sort(edge+1,edge+1+m);
    	int last=0;
    	bitset<Maxn+5> vis;
    	vis[0]=1;
    	int ans=Inf;
    	for(int i=1;i<=m;i++){
    		if(edge[i].d>=ans){
    			break;
    		}
    		quick_power(a,edge[i].d-last,vis);
    		last=edge[i].d;
    		queue<int> q;
    		a.a[edge[i].v][edge[i].u]=1;
    		for(int j=0;j<n;j++){
    			if(vis[j]){
    				dis[j]=0;
    				q.push(j);
    			}
    			else{
    				dis[j]=Inf;
    			}
    		}
    		while(!q.empty()){
    			int u=q.front();
    			q.pop();
    			for(int v=0;v<n;v++){
    				if(a.a[v][u]){
    					if(dis[v]==Inf){
    						dis[v]=dis[u]+1;
    						q.push(v);
    					}
    				}
    			}
    		}
    		ans=min(ans,dis[n-1]+edge[i].d);
    	}
    	if(ans==Inf){
    		puts("Impossible");
    	}
    	else{
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Qt之界面数据存储与获取(使用setUserData()和userData())
    UML中关联(Association)、聚合(Aggregation)和合成(Composition)之间的区别
    Entity Framework Model First下改变数据库脚本的生成方式
    keepalive学习
    函数、极限、连续
    C#集合基础与运用
    面向查询服务的参数化查询
    WinDbg 命令手册
    知识管理方法论
    项目管理Project
  • 原文地址:https://www.cnblogs.com/withhope/p/12431445.html
Copyright © 2011-2022 走看看