题意:
给定一个无向图,和两对起点终点,求两条最短路上的最多公共交点数。
题解:
首先有个很强的性质:
所有公共点必定连续。
可以用反证法证明:
若a,b 为公共点,且他们不连续。
因为他们不连续,所以a到b至少有两条长度不同都路
与a,b为最短路上的公共点矛盾,最短路长度必然是确定的。
用cnt[i][j]在做最短路的时候记录下从i到j的包含节点数最多的最短路。
因为公共点是连续的,所以可以枚举公共点的起点终点。
假设给定的两对起点终点为s1,e1,s2,e2
若dis[s1][i]+dis[i][j]+dis[j][e1]==dis[s1][e1],则i,j在s1到e1的最短路上,若他也在s2到e2的路上就可以,将cnt[i][j]与ans比较,记录下来。
代码:
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年1月15日, 上午10:56
*/
//这里cnt[i][j]记录的是i到j的边数。
#include <cstdlib>
#include <stdio.h>
#include <memory.h>
using namespace std;
#define MAXN 305
#define INF 200000000
/*
*
*/
int n,d[MAXN][MAXN],cnt[MAXN][MAXN],a[MAXN][MAXN];
void Floyd()
{
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cnt[i][j]=1;
for(i=1;i<=n;i++)
cnt[i][i]=0;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if (a[i][k]+a[k][j]<a[i][j])
{
a[i][j]=a[i][k]+a[k][j];
cnt[i][j]=cnt[i][k]+cnt[k][j];
}
else if (a[i][k]+a[k][j]==a[i][j]&&cnt[i][k]+cnt[k][j]>cnt[i][j])
{
cnt[i][j]=cnt[i][k]+cnt[k][j];
}
}
}
int dp(int s1,int e1,int s2,int e2)
{
int i,j,k,ans;
ans=-1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if ( (a[s1][i]+a[i][j]+a[j][e1]==a[s1][e1])&&(a[s1][e1]<INF)
&&(a[s2][i]+a[i][j]+a[j][e2]==a[s2][e2])&&(a[s2][e2]<INF)
&&(cnt[i][j]>ans) )
ans=cnt[i][j];
return ans+1;
}
int main(int argc, char** argv)
{
int i,m,j,x,y,z,s1,e1,s2,e2;
while(scanf("%d %d",&n,&m)!=EOF)
{
if (n==0&&m==0) break;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (i!=j)
a[i][j]=INF;
else a[i][j]=0;
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
if (a[x][y]>z)
a[x][y]=a[y][x]=z;
}
scanf("%d %d %d %d",&s1,&e1,&s2,&e2);
Floyd();
printf("%d/n",dp(s1,e1,s2,e2));
}
return 0;
}