[NOIP2014真题]寻找道路
来源:互联网 发布:origin软件官方下载 编辑:程序博客网 时间:2024/05/18 22:46
先给一个数据不水的提交址:http://uoj.ac/problem/19
题目背景
NOIP2014 提高组 Day2 试题。
题目描述
在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件 1 的情况下使路径最短。
注意:图 G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入格式
第一行有两个用一个空格隔开的整数 n 和 m,表示图有 n 个点和 m 条边。
接下来的 m 行每行 2 个整数 x、y,之间用一个空格隔开,表示有一条边从点 x 指向点y。
最后一行有两个用一个空格隔开的整数 s、t,表示起点为 s,终点为 t。
输出格式
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出 -1。
样例数据1
输入
3 2
1 2
2 1
1 3
输出
1
样例数据2
输入
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
输出
3
备注
【样例1说明】
如上图所示,箭头表示有向道路,圆点表示城市。起点 1 与终点 3 不连通,所以满足题目描述的路径不存在,故输出 -1。
【样例2说明】
如上图所示,满足条件的路径为 1->3->4->5。注意点 2 不能在答案路径中,因为点 2 连了一条边到点 6,而点 6 不与终点 5 连通。
【数据说明】
对于 30% 的数据,
对于 60% 的数据,
对于 100% 的数据,
分析: 这道题正着十分难做,考虑反着做。反向建图,从终点往起点走,走不到的地方便是正着走不直接或间接指向终点的点。给他们打上标记,并把与他们距离为1的点也打上标记。之后相当于删掉这些点和指向他们的边,构造新图走dijkstra(SPFA也可)。注意,要特判起点,因为在我的算法中是删掉指向不满足点的边,但是起点没有入边,所以被UOJhack数据卡了。
代码:
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){ int f=1,sum=0; char ch; for(ch=getchar();(ch>'9'||ch<'0')&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;ch>='0'&&ch<='9';ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f;}int tot,x,y,n,m,s,t,dis[10010];bool bj1[10010],bj2[10010],visit[10010],exist[200010];int first1[10010],nxt1[200010],to1[200010],w[200010],first2[10010],nxt2[200010],to2[200010];queue<int> que; void addedge(int x,int y)//正反同时建边{ tot++; nxt1[tot]=first1[x]; first1[x]=tot; to1[tot]=y; w[tot]=1; nxt2[tot]=first2[y]; first2[y]=tot; to2[tot]=x;}void dfs(int u){ bj1[u]=0; for(int p=first2[u];p;p=nxt2[p]) { int v=to2[p]; if(!visit[v]) { visit[v]=1; dfs(v); } }}void SPFA(){ dis[s]=0; que.push(s); visit[s]=1; while(!que.empty()) { int u=que.front(); que.pop(); visit[u]=0; for(int p=first1[u];p;p=nxt1[p]) { if(exist[p]) { int v=to1[p]; if(dis[v]>dis[u]+w[p]) { dis[v]=dis[u]+w[p]; if(!visit[v]) { visit[v]=1; que.push(v); } } } } }}int main(){ freopen("road.in","r",stdin); freopen("road.out","w",stdout); n=getint();m=getint(); for(int i=1;i<=m;++i) { x=getint();y=getint(); addedge(x,y); } s=getint();t=getint(); memset(bj1,1,sizeof(bj1));//把所有点都打标记,然后dfs删掉能走到的点的标记 dfs(t); for(int i=1;i<=n;++i)//与有标记的点距离为1的点也打上标记 if(bj1[i]) for(int p=first2[i];p;p=nxt2[p]) { int v=to2[p]; bj2[v]=1;//为什么要用新标记呢?因为用bj1会导致把与这些新标记的点距离为1的点也打上标记,如此恶性循环,整个图全是标记了。 } memset(exist,1,sizeof(exist)); for(int i=1;i<=tot;++i)//删边 { int v=to1[i]; if(bj1[v]==1||bj2[v]==1) exist[i]=0; } if(bj1[s]==1||bj2[s]==1)//特判起点 { cout<<-1<<endl; return 0; } memset(dis,127,sizeof(dis)); memset(visit,0,sizeof(visit)); SPFA(); if(dis[t]>200000)//终点没更新,就是走不通 cout<<-1<<endl; else cout<<dis[t]<<endl; return 0;}
本题结。
- [NOIP2014真题]寻找道路
- Noip2014寻找道路题解
- NOIP2014 寻找道路
- [NOIP2014]寻找道路
- NOIP2014寻找道路
- vijos1909【noip2014】寻找道路
- 【noip2014】寻找道路
- NOIP2014 寻找道路
- noip2014寻找道路
- 【NOIP2014】D2T2 寻找道路
- 【noip2014】tyvj4058 寻找道路
- noip2014寻找道路
- noip2014 寻找道路
- [NOIP2014]寻找道路
- noip2014寻找道路
- [NOIP2014]寻找道路
- [NOIP2014][建图]寻找道路
- [noip2014]寻找道路 题解
- 深入理解JVM方法调用的内部机制
- c++set讲解
- antd
- 主流消息队列应用场景
- Python--python数据挖掘领域工具包
- [NOIP2014真题]寻找道路
- 截屏与截长图功能的实现
- Java 工具类
- Http状态码详解
- 概率统计——两个变量之间的度量
- Getting Started
- git工具的使用
- vs下调试变量无法添加到监视或者无法打断点
- selenium--关键字驱动