WuKong-HDU2833

42 篇文章 0 订阅

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2833

题意:给定无向图,求两条最短路A->B,C->D,问这两条最短路的公共点最多有多少个

思路:1:floyd预处理所有点对最短路:

          2:记忆化搜索:

首先A->B的最短路径,可以形成一棵有根树,

沿着A->B的最短路径形成的树,从A开始搜索,

dp[u],表示从u->B,两条最短路的最多公共定点数

if(edge(u->v)在A->B和C->D最短路径树上)dp[u]=max(dp[u],dp[v]+1);

else dp[u]=max(dp[u],dp[v]);

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

const int N=310;
const int M=310*310*2;
const int INF=1<<30;
int map[N][N];
int dp[N];
int vis[N];
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline int max(int a,int b)
{
    return a>b?a:b;
}

struct Edge
{
    int to,next,w;
}e[M];
int total,head[N];
void add_edges(int from,int to,int w)
{
    e[total].to=to,e[total].next=head[from],e[total].w=w,head[from]=total++;
}
void init()
{
    total=0;memset(head,-1,sizeof(head));
}

void floyd(int n)
{
    for(int k=0;k<n;k++)
    {
        for(int i=0;i<n;i++)
        {
            if(map[i][k]==INF)continue;
            for(int j=0;j<n;j++)
            {
                if(map[k][j]==INF)continue;
                map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
            }
        }
    }
}
int s1,t1,s2,t2;

inline int f(int u)
{
    if(map[s2][u]==INF||map[u][t2]==INF||map[s2][t2]!=map[s2][u]+map[u][t2])return 0;
    return 1;
}
void dfs(int u)
{
    int ans=0;
    vis[u]=1;
    int cnt=0;
    int flag=f(u);
    if(u==t1)
    {
        dp[u]=flag;
        return ;
    }
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(map[v][t1]==INF)continue;
        if(map[u][t1]==map[v][t1]+e[i].w)
        {
            if(flag&&((map[u][t2]==map[v][t2]+e[i].w)||u==t2))cnt=1;
            else cnt=0;
            if(vis[v])
            {
                ans=max(ans,dp[v]+cnt);
            }
            else
            {
                dfs(v);
                ans=max(ans,dp[v]+cnt);
            }
        }
    }
    if(!ans&&flag)ans=1;表示u是第一个公共点
    dp[u]=ans;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF,n||m)
    {
        init();
        for(int i=0;i<n;i++)
        {
            map[i][i]=0;
            for(int j=i+1;j<n;j++)
            {
                map[i][j]=map[j][i]=INF;
            }
        }
        for(int i=0;i<m;i++)
        {
            int a,b,c;scanf("%d%d%d",&a,&b,&c);a--;b--;
            add_edges(a,b,c);add_edges(b,a,c);
            map[a][b]=map[b][a]=min(map[a][b],c);
        }
        floyd(n);
        memset(vis,0,sizeof(vis));
        scanf("%d%d%d%d",&s1,&t1,&s2,&t2);s1--;t1--;s2--;t2--;
        /*for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                printf("%d,",map[i][j]);
            }printf("\n");
        }*/
        if(map[s1][t1]==INF||map[s2][t2]==INF)
        {
            //printf("line1\n");
            printf("0\n");continue;
        }
        dfs(s1);
        //for(int i=0;i<n;i++){printf("%d--%d,",i+1,dp[i]);}
        printf("%d\n",dp[s1]);
    }
    return 0;
}

p[v]);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值