CF1442C Graph Transpositions 01BFS

题意:

戳这里

分析:

  • 暴力

建分层图,直接跑最短路,把翻转次数当做最短路的状态之一,然后枚举最后的翻转状态

  • 正解

我们发现翻转次数最劣情况下会达到 (O(n)) ,所以复杂度成了 (O(n^2))

那么我们考虑如何优化,我们发现一个很显然的结论

当翻转次数超过 (O(log n)) 时,翻转一次的代价远大于遍历一遍整个图

所以我们把跑最短路时的翻转次数分成两部分,一部分是到这个点时至少翻转多少次,另一部分就是从这个点出发翻转多少次

我们把第一部分取掉,然后最短路的状态点数就变成了 (O(18n)) 的,就可以过了

第一部分可以 01BFS 预处理出来,最后枚举翻转了多少次

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define fir first
#define sec second

using namespace std;

namespace zzc
{
	inline long long read()
	{
		long long x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxn = 2e5+5;
	const long long mod = 998244353;
	const long long inf = 0x3f3f3f3f3f3f;
	long long head[maxn],dis[maxn][20],tim[maxn],pw[1000005];
	long long n,m,cnt=0,ans;
	deque<long long> d;
	queue<pii> q;
	
	struct edge
	{
		int to,nxt,dir;
	}e[maxn<<1];
	
	void add(int u,int v,int w)
	{
		e[++cnt].to=v;
		e[cnt].dir=w;
		e[cnt].nxt=head[u];
		head[u]=cnt;
	}
	
	void bfs1()
	{
		memset(tim,0x3f,sizeof(tim));
		d.clear();tim[1]=0;
		d.push_front(1);
		while(!d.empty())
		{
			int u=d.front();d.pop_front();
			for(int i=head[u];i;i=e[i].nxt)
			{
				int v=e[i].to;
				if(e[i].dir==(tim[u]&1))//ûÓз­×ª 
				{
					if(tim[v]>tim[u])
					{
						tim[v]=tim[u];
						d.push_front(v);
					}
				}
				else
				{
					if(tim[v]>tim[u]+1)
					{
						tim[v]=tim[u]+1;
						d.push_back(v);
					}
				}
			}
		}
	}
	
	void bfs2()
	{
		memset(dis,0x3f,sizeof(dis));
		dis[1][0]=0;
		q.push(mk(1,0));
		while(!q.empty())
		{
			int u=q.front().fir,w=q.front().sec;q.pop();
			for(int i=head[u];i;i=e[i].nxt)
			{
				int v=e[i].to;
				if(w+((w&1)!=e[i].dir)>=tim[v]+20) continue;
				if(dis[v][w+((w&1)!=e[i].dir)-tim[v]]>dis[u][w-tim[u]]+1)
				{
					dis[v][w+((w&1)!=e[i].dir)-tim[v]]=dis[u][w-tim[u]]+1;
					q.push(mk(v,w+((w&1)!=e[i].dir)));
				}
			}
			
		}
	}
	
	void work()
	{
		int a,b;
		pw[0]=1;ans=inf;
		for(int i=1;i<=35;i++) pw[i]=pw[i-1]*2%mod;
		for(int i=36;i<=1000000;i++) pw[i]=pw[i-1]*2%mod;
		n=read();m=read();
		for(int i=1;i<=m;i++)
		{
			a=read();b=read();
			add(a,b,0);add(b,a,1);
		}
		bfs1();
		bfs2();
		for(int i=0;i<=20;i++)
		{
			if(tim[n]+i>20&&ans!=inf) break;
			ans=min(ans,pw[i+tim[n]]-1+dis[n][i]);
		}
		printf("%lld
",ans%mod);
	}

}

int main()
{
	zzc::work();
	return 0;
}

原文地址:https://www.cnblogs.com/youth518/p/14070656.html