CQOI 1163 有向图的单源点最短路径

题目描述
给定有向无权图,求指定源点S到目标点T的最短路径(路径长度定义为从S到T经过的边的条数)。


输入
第1行:2个空格分开的整数n(2≤n≤200)和m(10≤m≤20000),分别表示图的顶点数和边数。


第2..m+1行:每行2个空格分开的整数i,j,i表示一条边的起点,j表示终点。


第m+2行:2个整数S, T。S表示源点,T表示目标点。


输出
第1行:1个整数,表示从S到T的最短路径的长度。如果从S到T没有路径,输出"no solution"。如果存在路径,则输出第2行,否则无第2行。


第2行:1个顶点序列,表示从s到t的最短路径。每2个顶点之间用1个空格分开。如果S==T,则只输出一个点。


如果有多组解,输出字典序最小的解。


样例输入


5 8
3 5
4 5
4 3 
2 3
5 4
4 1
4 2
2 4
3 2
样例输出
3

3 5 4 2

这题一看就知道可以用动态规划的方法做,但是由于范围较小而且时间问题,我使用了BFS的方法。运用队列(queue)进行搜索。具体操作如下:

f.push(a);

do{
for(int i=1;i<=n;i++)
{
if(c[f.front()][i]&&vis[i]==0)
{
vis[i]=1;
e[i]=f.front();
if(e[T]&&sum==0)
{
print(T);
}
f.push(i);
c[f.front()][i]=0;
}
}

f.pop();
}while(!f.empty());

其中要注意: if(e[T]&&sum==0)
{
print(T);
}

e这个数组中装的是第T个元素的父元素。print函数是用来打印过程的,sum则是最短步数,如下:

void print(int a)
{
if(a==S)
{
printf("%d\n%d",sum,a);
return;
}
sum++;
if(a!=S)
{
print(e[a]);
printf(" %d",a);
}
}

起点和终点重合就只能打表了,看吧:

if(S==T)
{
printf("0\n%d",S);
return 0;
}

全代码:

#include<cstdio>
#include<stack>
#include<cstring>
#include<queue>
using namespace std;
int c[201][201],e[201],vis[201];
queue<int>f;
int n,m,x,y,S,T,sum;
void print(int a)
{
if(a==S)
{
printf("%d\n%d",sum,a);
return;
}
sum++;
if(a!=S)
{
print(e[a]);
printf(" %d",a);
}
}
void count(int a)
{
f.push(a);
do{
for(int i=1;i<=n;i++)
{
if(c[f.front()][i]&&vis[i]==0)
{
vis[i]=1;
e[i]=f.front();
if(e[T]&&sum==0)
{
print(T);
}
f.push(i);
c[f.front()][i]=0;
}
}

f.pop();
}while(!f.empty());
if(sum==0&&S!=T)
printf("no solution");
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
c[x][y]=1;
}
scanf("%d%d",&S,&T);
if(S==T)
{
printf("0\n%d",S);
return 0;
}
count(S);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/52330872
今日推荐