HDU 2433(Travel) 最短路问题(SPFA)

题目大概是说有n个顶点,m条边,然后按顺序删除这m条边,每次删除一条边,计算下一条边时前面被删除的边重新恢复,每次计算n个顶点通过m-1条边到其余n-1个顶点的的最短路之和。

不优化,直接删一条边算n次SPFA的话,TLE。这里可以通过优化,来减少时间。

优化点:

预处理:在删边之前先算一次每个顶点到n-1个最短路之和 保存至num[i]中(i为顶点编号)总和保存sum中,用pre[i][v]=u(顶点编号)记录计算i最短路时路径<u,v>,用mark[u][v][0](等于1或者0)来记录<u,v>是否在计算中出现过。

然后删除边<u,v>处理。

1.如果num[i]出现INF,直接INF(不删都到不了,删了更到不了);

2.如果有重边,那么你删一条,后面还有,删边不影响,直接输出sum;

3.没有重边:

1.如果<u,v>没有在计算sum中出现过(mark[u][v][0]),即都没有出现在任何n个顶点的最短路径中,那么删去<u,v>不影响,直接输出sum;

2.重新计算最短路和sum:

1.如果在计算第i个顶点到其它点最短路时,pre[i][u]!=v并且pre[i][v]!=u,即<u,v>没有出现在预处理的最短路径中,直接sum+=num[i];

2.<u,v>出现在预处理最短路径中,只能重新计算Spfa(i),sum+=Spfa(i)(Spfa(i)返回的是i顶点到其余顶点的最短路之和),如果有Spfa(i)=INF,结束计算循   环,输出INF,没有的话最后输出sum。

刚开始没有想到3.2.1这个优化点,直接TLE,说明这点优化相当重要。

还有我在网上看到别人说3.2.2中计算sum时 sum+=Spfa(u)-num[u]+Spfa(v)-num[v],没看明白,怎么证明这个公式??

SPFA:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAX_VERTEX 110
#define INF 0x3f3f3f3f 

int map[MAX_VERTEX][MAX_VERTEX],visit[MAX_VERTEX],q[MAX_VERTEX],dis[MAX_VERTEX];
int pre[MAX_VERTEX][MAX_VERTEX];
int mark[MAX_VERTEX][MAX_VERTEX][5];
int num[MAX_VERTEX];
int aa[3010],bb[3010];
int vex,arc,sum;
int flag;
int Spfa(int s)
{
    int rear,front,i,pos;
    int sum1,sum2,vexnum;
    memset(visit,0,sizeof(visit));
    memset(dis,0x3f,sizeof(dis));
    memset(q,0,sizeof(q));
    rear=front=0;
    q[rear]=s;
    visit[s]=1;
    rear++;
    dis[s]=0;
    sum1=0;
//    sum2=0;
    //vexnum=0;
    while(front<rear)
    {
        pos=q[front];
        visit[pos]=0;
        front++;
        //sum2+=dis[pos];
        //vexnum++;
        for(i=1;i<=vex;i++)
        {
            if(i==pos) continue;
            if(dis[i]>dis[pos]+1 && map[pos][i]>0)
            {
                dis[i]=dis[pos]+1;
                if(flag==0)
                {
                    pre[s][i]=pos;
                    mark[pos][i][flag]=mark[i][pos][flag]=1;
                } 
                if(!visit[i])
                {
                    q[rear]=i;
                    visit[i]=1;
                    rear++;
                }
            }
        }
    }
/*    if(vexnum<vex) return INF;
    else return sum2;*/
    for(i=1;i<=vex;i++)
    {
        if(dis[i]==INF)
        {
             return INF;
             break;
        }
        else sum1+=dis[i];
    }
    return sum1;
}
int main()
{
    int i,j,sum2;
    while(scanf("%d%d",&vex,&arc)!=EOF)
    {
        memset(map,0,sizeof(map));
        memset(aa,0,sizeof(aa));
        memset(bb,0,sizeof(bb));
        memset(pre,0,sizeof(pre));
        memset(num,0,sizeof(num));
        memset(mark,0,sizeof(mark));
        for(i=0;i<arc;i++)
        {
            scanf("%d%d",&aa[i],&bb[i]);
            map[aa[i]][bb[i]]++;
            map[bb[i]][aa[i]]++;
        }
        sum=0;
        flag=0;
        for(i=1;i<=vex;i++)
        {
             if(Spfa(i)==INF) 
             {    
                 sum=INF;
                 break;
             }
             num[i]=Spfa(i);
            sum+=num[i];
        }
        flag=1;
        for(i=0;i<arc;i++)
        {
            if(sum==INF)
            {
                printf("INF\n");
                continue;
            } 
            map[aa[i]][bb[i]]--;
            map[bb[i]][aa[i]]--;
            if(map[aa[i]][bb[i]]>0)
            {
                printf("%d\n",sum);
                map[aa[i]][bb[i]]++;
                map[bb[i]][aa[i]]++;
            } 
            else
            {
                sum2=0;
                for(j=1;j<=vex;j++)
                {
                    if(mark[aa[i]][bb[i]][0]==0)
                    {
                        printf("%d\n",sum);
                    }
                    if(pre[j][aa[i]]!=bb[i] && pre[j][bb[i]]!=aa[i])
                    {
                        sum2+=num[j];
                    }
                    else
                    {
                        sum2+=Spfa(j);
                        if(sum2==INF) break;
                    }
                }
                if(sum2<INF) printf("%d\n",sum2);
                else
                    printf("INF\n");
                map[aa[i]][bb[i]]++;
                map[bb[i]][aa[i]]++;    
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值