时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述 

由于阿鸡太美了,所以有着非常多的粉丝,今天他要从酒店前往CTRL(Chang·Tiao·Rap·Lanqiu)大赛现场。但由于狂热粉丝太多了,粉丝们都堵在路上等待着阿鸡,所以阿鸡想要节约时间,尽量避免被粉丝拦下。

给定一张无自环无重边的无向图,在某些边上打上箭头,沿着箭头方向走过某一条边会粉丝被拦截一次,阿鸡每沿着箭头方向经过一条边时,被拦截次数加一。所以阿鸡想要从酒店到达CTRL大赛现场时被拦截次数最少。希望作为iji的你告诉他最小的被拦截次数。酒店为 11 号结点,CTRL大赛现场为 nn 号结点。

若无法到达CTRL大赛现场,你需要告诉阿鸡“How about we explore the area ahead of us later?”。

输入描述:

第一行两个整数 n(1 \le n \le 10^5),m(1 \le m \le min(\frac{n \times (n-1)}{2} , 2\times 10^5))n(1n105),m(1mmin(2n×(n1),2×105)) 分别表示无向图顶点数及边数。

接下来 mm 行,每行两个正整数 u,v(1 \le u,v \le n,u \ne v)u,v(1u,vn,u=v) 表示 u,vu,v 之间连有一条边。

接下来一行一个正整数 q(1 \le q \le min(\frac{n \times (n-1)}{2} , 2\times 10^5))q(1qmin(2n×(n1),2×105)) 表示打箭头的边数。

接下来 qq 行,每行两个正整数 u,v(1 \le u,v \le n,u \neq v)u,v(1u,vn,u=v) 表示 uu 到 vv 之间打上了箭头(保证 u,vu,v 之间原先有边)。

输出描述:

输出一个正整数,表示最小的被拦截次数。

若无法到达CTRL大赛现场,则输出“How about we explore the area ahead of us later?”。
示例1

输入

复制
4 5
1 2
3 1
2 3
2 4
4 3
4
1 2
3 2
3 4
2 4

输出

复制
1

说明

阿鸡可以从1走到3,再从3走到4,被拦截次数为1。可以发现没有更好的走法。
示例2

输入

复制
3 1
1 2
2
1 2
2 1

输出

复制
How about we explore the area ahead of us later?

说明

显然,结点1无法到达结点3。
 
#include <bits/stdc++.h>
#define fi first
#define se second 
using namespace std;
const int N=1e5+10; 
const int M=2e5+10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int,int>PII;
typedef pair<LL,LL>PLL;

//只可以采用堆优化版的dijstra的
int idx=1,head[4*N],ne[4*N],ver[4*N],val[4*N];//注意从第一个地方开始,结尾是0 
int dist[N];//注意这里是从2倍开始的
priority_queue<PII,vector<PII>,greater<PII> >heap;
bool vis[N];
int n,m,q;
void add(int x,int y,int c)
{
	ne[idx]=head[x],ver[idx]=y,val[idx]=c,head[x]=idx++;
}
void modify(int x,int y)
{
	for(int i=head[x];i;i=ne[i])
	{
		int z=ver[i];
		if(z==y)val[i]=1;//这里是y
	}
}

int dijstra()
{
	    memset(dist,0x3f,sizeof dist);
		dist[1]=0;//vis[1]=1;//第一个状态没有设置
		heap.push({0,1});//默认的是对第一个数值进行排序的
		
		while(heap.size())
		{
			auto c=heap.top();
			heap.pop();
			int x=c.second,y=c.first;//分别代表着结点和距离
			if(vis[x])continue;//之前进行遍历过
			
			//选出结点 
			vis[x]=1;
			
			for(int i=head[x];i;i=ne[i])
			{//确定点的时候必须是之前没有确定过的,但是优化边的时候额可以是以前遍历过的 
				if(dist[ver[i]]>dist[x]+val[i])
				{
					dist[ver[i]]=dist[x]+val[i];
					heap.push({dist[ver[i]],ver[i]});
				}
				
			} 
					
		}
		 if(dist[n]==0x3f3f3f3f)return -1;
		 return dist[n];
}
int main()
{
	//有链接权值就是0,没有链接权值就是INF,有拦截权值就是1; 
	scanf("%d%d",&n,&m);
	/*for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);	
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
	    modify(u,v);
	}*///两次寻找太过于暴力
    map<pair<int,int>,int>s;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        s[{u,v}]=0,s[{v,u}]=0;
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        s[{u,v}]=1;
    }
    for(auto i:s) add(i.first.first,i.first.second,i.second);
    
	int c=dijstra();
	if(c==-1)cout<<"How about we explore the area ahead of us later?"<<endl;
    else printf("%d",c);
    return 0;
}

  注意这里:

1》之前 对于1的边,再在0的边中寻找,时间复杂度过高超时。可以采用map 或set 先进行去重改变,减低时间复杂度

2》数组大小一般是边数的两倍,不管是否为无向图

 

posted on 2022-11-22 00:23  浅唱\,,笑竹神易  阅读(149)  评论(0)    收藏  举报