[質問の解決策]方法を見つける

件名ソース:Loge

タイトル説明

有向グラフGでは、各辺の長さは1です。ここで、始点と終点が与えられたので、グラフの始点から終点までのパスを見つけてください。パスは次の条件を満たしています。

1.パス上のすべてのポイントの外側のエッジが指すポイントは、直接または間接的にエンドポイントに接続されます。
2.条件1が満たされた場合は、パスを最短にします。
注:グラフGには複数のエッジと自己ループが存在する可能性があり、問題により、エンドポイントからのエッジがないことが保証されます。

条件を満たすパスの長さを出力してください。

入力フォーマット

最初の線には、スペースで区切られた2つの整数nとmがあります。これは、グラフにn個のポイントとm個のエッジがあることを意味します。

次のm行には、各行に2つの整数x、yがあり、スペースで区切られています。これは、ポイントxからポイントyにエッジがあることを示します。

最後の行にスペースで区切られた2つの整数sがあり、開始点がsで、終了点がtであることを示します。

出力フォーマット

出力は、タイトルの説明を満たす最短パスの長さを示す整数を含む1行のみです。そのようなパスが存在しない場合は、-1を出力します。

入力例1

3 2
1 2
2 1
1 3

サンプル出力1

-1

入力例2

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

サンプル出力2

3
指示/プロンプト
説明1:
ここに写真の説明を挿入

上の図に示すように、矢印は有向道路を示し、点は都市を示します。始点11と終点33が接続されていないため、問題記述を満たすパスが存在しないため、-1-1を出力します。

説明2:
ここに写真の説明を挿入

上の図に示すように、条件を満たすパスは1-> 3-> 4-> 5です。ポイント2はエッジをポイント6に接続し、ポイント6はエンドポイント5に接続されていないため、ポイント2を応答パスに含めることはできないことに注意してください。

【データ範囲】

データの30%について、0 <n≤10、0 <m≤20;

データの60%について、0 <n≤100、0 <m <m≤2000;

100%データの場合、0 <n≤10000、0 <m≤200000、0 <x、y、s、t≤n、x、s≠t。

アイデア:

参照の解決策は、この問題
なければならないのである:
1、すべての反対側、エンドからのED開始BFS、エンド・マーキング編の開始点が来るかもしれません

2.各ポイントを列挙します。ポイントがマークされていない場合は、その出力エッジをそれぞれ列挙します(反転)。ポイントがマークされている場合は、マークされているポイントが不正であることを意味します。削除、
2番目の配列マークを付けることをお勧めします。配列内のポイントを削除すると後遺症タイプになります。ポイントがマークされ始めると、シリアル番号の小さいポイントから削除され、アクセスされると、最初にマークされていなかったポイントとみなされ、合法的なポイントは削除されます。
上記は_kong_のブログからのものです

3.リーガルポイント上の単一のソースポイントから最短パスを取ります

コード:(少し長いですが、アイデアは明確です)

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,m,st,ed,vis[N],vis1[N],dis[N],x[N],y[N];
vector <int> a[N],b[N];
queue <int> q;
void bfs(int s) //反向标记 
{
    
    
	q.push(s);
	while (!q.empty())
	{
    
    
		int t=q.front();
		q.pop();
		vis[t]=1;
		for (int i=0;i<b[t].size();i++)
		{
    
    
			int to=b[t][i];
			if (vis[to]==0)
			{
    
    
				q.push(to);
				vis[to]=1;
			}
		}
	}
}

void cancel()
{
    
    
	memcpy(vis1,vis,sizeof(vis));
	for (int i=1;i<=n;i++)
	  if (vis[i]==0)
	  {
    
    
          for (int j=0;j<b[i].size();j++) 
	        vis1[b[i][j]]=0;
	  }
	for (int i=1;i<=n;i++)
	{
    
    
	    if (vis1[i]==0)
		{
    
    
		    for (int j=0;j<a[i].size();j++)
			  a[i][j]=0;	
		}	
	} 
}

void init()
{
    
    
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
    
    
		int x,y;
		scanf("%d%d",&x,&y);
		if (x==y) continue;
		a[x].push_back(y);//正向边 
		b[y].push_back(x);//反向边 
	}
	scanf("%d%d",&st,&ed);
}

void spfa(int s)
{
    
    
	while (!q.empty()) q.pop();
	for (int i=1;i<=n;i++) dis[i]=99999999,vis[i]=0;
	dis[s]=0;
	q.push(s);
	vis[s]=1;
	while (!q.empty())
	{
    
    
		int t=q.front();
		q.pop();
		vis[t]=1;
		for (int i=0;i<a[t].size();i++)
		{
    
    
			int to=a[t][i];
			if (dis[to]>dis[t]+1)
			{
    
    
				dis[to]=dis[t]+1;
				if (vis[to]==0)
				{
    
    
					q.push(to);
					vis[to]=1;
				}
			}
		}
	}
}
int main()
{
    
    
	init();
	bfs(ed); //从终点反向标记 	

    if (vis[ed]==0)  //起点无法到达终点就直接结束程序 
    {
    
    
    	cout<<-1<<endl;
    	return 0;
	}

	cancel();//撤去不符合条件的点	
	
	spfa(st);//单元点最短路 
	if (dis[ed]==99999999) cout<<-1<<endl;
	else cout<<dis[ed]<<endl;
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_45485187/article/details/102750099