传送门

s 1 − > t 1 s1->t1 s1>t1的最短路和 s 2 − > t 2 s2->t2 s2>t2的最多相同节点


肯定从点 t 1 , t 2 t1,t2 t1,t2开始跑最短路

这样从 s 1 , s 2 s1,s2 s1,s2出发只能走最短路上的边

而且如果定义 f [ i ] [ j ] f[i][j] f[i][j]为第一条路在 i i i,第二条路在 j j j时,还能相同的最多点数

显然终止条件 f [ t 1 ] [ t 2 ] f[t1][t2] f[t1][t2] 0 0 0

而且因为只能走最短路边,所以是一个 D A G DAG DAG

这样记忆化搜索就不许需要担心卡死

爆搜即可

#include <bits/stdc++.h>
using namespace std;
const int N = 309;
const int inf = 2e9+1;
struct edge{
	int to,nxt,w;
}d[N*N*2]; int head[N*N*2],cnt=1;
void add(int u,int v,int w)
{
	d[++cnt].to=v,d[cnt].nxt = head[u],d[cnt].w=w,head[u] = cnt;
}
int dis1[N],dis2[N],n,m,vis[N];
typedef pair<int,int>p;
void dijstra(int s,int dis[])
{
	for(int i=1;i<=300;i++)	dis[i] = inf, vis[i] = 0;
	priority_queue<p,vector<p>,greater<p> >q; q.push( p(0,s) );
	dis[s] = 0;
	while( !q.empty() )
	{
		int u = q.top().second; q.pop();
		if( vis[u] )	continue;
		vis[u] = 1;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v = d[i].to;
			if( dis[v]>dis[u]+d[i].w )
			{
				dis[v] = dis[u]+d[i].w;
				q.push( p(dis[v],v) );	
			}	
		}	
	} 
}
int f[N][N],s1,s2,t1,t2;
int dfs(int u1,int u2)
{
	if( u1==t1&&u2==t2 )	return 0;
	if( f[u1][u2]!=-1 )	return f[u1][u2];
	for(int i=head[u1];i;i=d[i].nxt )//u1先走 
	{
		int v = d[i].to;
		if( dis1[v]!=dis1[u1]-d[i].w )	continue;	
		f[u1][u2] = max( f[u1][u2],dfs(v,u2)+(v==u2) );
	}
	for(int i=head[u2];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( dis2[v]!=dis2[u2]-d[i].w )	continue;
		f[u1][u2] = max( f[u1][u2],dfs(u1,v)+(v==u1) );
	}
	return f[u1][u2];
}
int main()
{
	while( cin >> n >> m && (n+m) )
	{
		for(int i=1;i<=m;i++)
		{
			int l,r,w; scanf("%d%d%d",&l,&r,&w);
			if( l==r )	continue;
			add(l,r,w); add(r,l,w);
		}
		cin >> s1 >> t1 >> s2 >> t2;
		dijstra(t1,dis1); dijstra(t2,dis2);
		memset( f,-1,sizeof f );
		cout << dfs(s1,s2)+(s1==s2) << '\n';
		cnt = 1;
		for(int i=1;i<=300;i++)	head[i] = 0;
	}
}