CodeForces - 1529F It‘s a bird! No, it‘s a plane! No, it‘s AaParsa!(最短路+思维建图)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 1529F It‘s a bird! No, it‘s a plane! No, it‘s AaParsa!(最短路+思维建图)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出 n n n 个点(从 0 0 0 开始编号)和 m m m 条边的有向带权图,不过 m m m 条边是动态的,经过 t t t 秒后,第 i i i 条边就从 a i − > b i , c i a_i->b_i,c_i ai>bi,ci 变成了 a i − > ( b i + t ) m o d    n , c i a_i->(b_i+t)\\mod{n},c_i ai>(bi+t)modn,ci,现在要求输出任意两点之间的最短路(最短路矩阵)

注意:在达到某个点后可以选择停留任意时刻再继续赶路

题目分析:读完题后不难建出分层图最短路的模型,共有 n ∗ n n*n nn 个点和 m ∗ n m*n mn 条边,直接跑 Floyd 的话是 O ( n 6 ) O(n^6) O(n6),跑 n n n 次 Dijkstra 的话是 O ( n ∗ m ∗ n ∗ l o g ( n ∗ n ) ) = O ( n 4 l o g n ) O(n*m*n*log(n*n))=O(n^4logn) O(nmnlog(nn))=O(n4logn),所以分层图的想法只能 pass 了

是赛后看题解补的题,发现模型很巧妙,如果没有停留时间的限制,就是一个裸的迪杰斯特拉了(不需要分层图,每个点贪心松弛即可)

加上了停留时间的限制,我们可以对于每个点 i i i ,添加一条 i − > ( i + 1 ) m o d    n , 1 i->(i+1)\\mod n,1 i>(i+1)modn,1
也就是相邻的两个点添加一条花费为 1 1 1 的道路,为什么这样建图是可行的呢?假设现在点 u u u,可以到达点 v v v,若我们想要到达点 v + k v+k v+k 的话,只需要在点 u u u 先等上 k k k 秒,然后就可以直接走 u − > ( v + k ) u->(v+k) u>(v+k) 这条边了,等效于先走 u − > v u->v u>v 然后每一秒依次走 v − > v + 1 v->v+1 v>v+1 v + 1 − > v + 2 v+1->v+2 v+1>v+2 等等等等

需要注意的是,第一条边不能走 i − > i + 1 i->i+1 i>i+1 这条边,所以在写最短路的时候,我们需要手动松弛第一次

还需要注意的是,初始时可能会存在重边(参考样例二),所以我们初始化邻接矩阵时,应该将 i = = j i==j i==j 的位置也初始化为无穷大才行

因为这个题目时间卡的很紧,所以在选择算法的时候需要选择 O ( n 2 ) O(n^2) O(n2) 的迪杰斯特拉,因为在稠密图上跑堆优化的迪杰斯特拉,时间复杂度是 O ( m l o g n ) = O ( n 2 l o g n ) O(mlogn)=O(n^2logn) O(mlogn)=O(n2logn)

代码:

// Problem: F. It's a bird! No, it's a plane! No, it's AaParsa!
// Contest: Codeforces - Codeforces Round #722 (Div. 2)
// URL: https://codeforces.com/contest/1529/problem/F
// Memory Limit: 256 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const LL inf=0x3f3f3f3f3f3f3f3f;
const int N=610;
LL maze[N][N],d[N];
bool vis[N];
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n,m;
	read(n),read(m);
	memset(maze,0x3f,sizeof(maze));
	while(m--) {
		int u,v,w;
		read(u),read(v),read(w);
		maze[u][v]=w;
	}
	for(int i=0;i<n;i++) {
		memset(d,0x3f,sizeof(d));
		memset(vis,false,sizeof(vis));
		for(int j=0;j<n;j++) {
			d[j]=min(d[j],maze[i][j]);
		}
		while(1) {
			LL mmin=inf;
			int mark=-1;
			for(int j=0;j<n;j++) {
				if(!vis[j]&&(mark==-1||d[j]<mmin)) {
					mmin=d[j];
					mark=j;
				}
			}
			if(mark==-1) {
				break;
			}
			vis[mark]=true;
			d[(mark+1)%n]=min(d[(mark+1)%n],d[mark]+1);
			for(int j=0;j<n;j++) {
				d[(j+d[mark])%n]=min(d[(j+d[mark])%n],d[mark]+maze[mark][j]);
			}
		}
		for(int j=0;j<n;j++) {
			if(i==j) {
				cout<<0<<' ';
			} else {
				printf("%lld ",d[j]);
			}
		}
		puts("");
	}
	return 0;
}

以上是关于CodeForces - 1529F It‘s a bird! No, it‘s a plane! No, it‘s AaParsa!(最短路+思维建图)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 1000B Light It Up(思维)

AC日记——Is it rated? codeforces 807a

B. Just Eat It! CodeForces1285B

Codeforces 1630 E Making It Bipartite 题解 (Dilworth定理)

Codeforces Round #613 (Div. 2) B. Just Eat It!

CodeForces 1000B Light It Up(贪心思维)