WuKong 最短路加DP HDU 2833

题意:

 给定一个无向图,和两对起点终点,求两条最短路上的最多公共交点数。

题解:

首先有个很强的性质:

  所有公共点必定连续。

可以用反证法证明:

若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;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值