CodeForces - 1321D Navigation S.ystem(最短路+思维)

题目链接:点击查看

题目大意:给出一个由 n 个点和 m 条边组成的有向图,现在有一个人,他有一条固定的路线,这个题目中有一个导航,当到达任意一个点时,导航都会给出一条通往终点的最短路,但是这个人固定的路线并不一定每次都是最短路,导航最初会给出一条最短路,如果这个人不按照最短路行走的话,那么导航需要“重构”最短路,题目问“重构”的最小次数和最大次数

题目分析:其实读完题后,首先第一反应是先将所有的边置反,然后对于终点求一次迪杰斯特拉,因为这是CF,怕hack,所以尽量还是别用spfa吧,然后题目给出的固定路线中有 k 个点,即 k - 1 条边,对于每条边判断,无非只有三种情况,我们记ans0为最小次数,ans1为最大次数:设这条边为 u -> v

  1. 当前边不是最短路上的边,那么无论如何走,从点 u 到点 v 后,导航一定会重构一次最短路,那么ans0++,ans1++
  2. 当前边是最短路上的边,显然ans0不变,因为选择当前路就可以使得最短路最短,且无需重构
    1. 如果当前边是最短路的必经边,也就是从点 u 到终点只有 u ->v 这一条最短路满足路程最短,ans1不变,因为没有其他选择了
    2. 如果当前边不是最短路的必经边,那么必然存在另一条边 u -> t 满足点 u 到终点的距离仍然是最短路,此时选择 u -> t 这条路可以使ans1++

然后直接模拟上述三种情况就好了,为了方便书写,迪杰斯特拉我用了链式前向星的模板,建立反向边,而正向边仍然用邻接表储存,用于最后统计答案时用

代码:
 

#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>
using namespace std;
      
typedef long long LL;
     
typedef unsigned long long ull;
      
const int inf=0x3f3f3f3f;
 
const int N=2e5+100;//顶点数 

const int M=2e5+100;//边数

struct Edge
{
	int to,w,next;
}edge[M];

int head[N],d[N],cnt;//链式前向星 

bool vis[N];

void addedge(int u,int v,int w)
{
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}

struct Node
{
	int to,w;
	Node(int TO,int W)
	{
		to=TO;
		w=W;
	}
	bool operator<(const Node& a)const
	{
		return w>a.w;
	}
};

void Dijkstra(int st)
{
	priority_queue<Node>q;
	memset(vis,false,sizeof(vis));
	memset(d,inf,sizeof(d));
	d[st]=0;
	q.push(Node(st,0));
	while(q.size())
	{
		Node cur=q.top();
		int u=cur.to;
		q.pop();
		if(vis[u])
			continue;
		vis[u]=true;
		for(int i=head[u];i!=-1;i=edge[i].next)//扫描出所有边 
		{
			int v=edge[i].to;
			int w=edge[i].w;
			if(d[v]>d[u]+w)//更新 
			{
				d[v]=d[u]+w;
				q.push(Node(v,d[v]));
			}
		}
	}
}

void init()
{
	memset(head,-1,sizeof(head));
	cnt=0; 
}

vector<int>node[N];

int a[N];

int main()
{
#ifndef ONLINE_JUDGE
//	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	init();
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		node[u].push_back(v);
		addedge(v,u,1);
	}
	int k;
	scanf("%d",&k);
	for(int i=1;i<=k;i++)
		scanf("%d",a+i);
	Dijkstra(a[k]);
	int ans_0=0,ans_1=0;
	int u=a[1];
	int dis=d[u];
	for(int i=2;i<=k;i++)
	{
		int v=a[i];
		if(d[u]!=d[v]+1)//新加的边不在最短路上
		{
			ans_1++,ans_0++;
		}
		else//在最短路上
		{
			for(auto vv:node[u])
			{
				if(vv==v)
					continue;
				if(d[u]==d[vv]+1)
				{
					ans_1++;
					break;
				}
			}
		}
		u=v;
	}
	printf("%d %d\n",ans_0,ans_1);


	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
发布了672 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104617167