HDU-2433 Travel(最短路[Dijkstra])

博客探讨了HDU-2433 Travel问题,涉及多组输入和边数的最短路径计算。内容指出,仅删除一条边时,某些两点间最短路径会发生变化。文章讨论了通过记录路径和不记录路径的两种方法,并提到了一种使用used矩阵来跟踪路径状态的高效解决方案,以避免超时错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Travel

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
      One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will always take the shortest way. There are M (M <= 3000) two-way roads connecting the towns, and the length of the road is 1.
      Let SUM be the total distance of the shortest paths between all pairs of the towns. Please write a program to calculate the new SUM after one of the M roads is destroyed.

 

Input
      The input contains several test cases.
      The first line contains two positive integers N, M. The following M lines each contains two integers u, v, meaning there is a two-way road between town u and v. The roads are numbered from 1 to M according to the order of the input.
      The input will be terminated by EOF.

 

Output
      Output M lines, the i-th line is the new SUM after the i-th road is destroyed. If the towns are not connected after the i-th road is destroyed, please output “INF” in the i-th line. 
 

Sample Input
5 4 5 1 1 3 3 2 5 4 2 2 1 2 1 2
 

Sample Output
INF INF INF INF 2 2


题目大意:多组输入,每组第一行读入定点数n和边数m,接下来m行是边。输出1~m条边分别摧毁后任意两点(分起点终点)的最短距离和,如果存在两点不连通,则INF


由于边数多,如果每次都计算任意两点的距离会超时。

看到大神的思路后,注意到每次只删除一条边,如果这条边在某两点(u,v)的最短路径中,则u,v两点的最短路长度会变,其他不变

但是太懒了,不想记录路径,又看到很多人直接只算(u,v)的最短路,然后减去原来u,v的最短路*2,加上最新的最短路*2就是答案,但这样的代码居然能AC,数据真是好水

例如这组数据就会挂很多人

4 4 
1 2
2 3
3 4 
2 4

答案:
INF
20
18
20


按照正确思路写出来,TLE,可能是太渣了,而且每对顶点都跑一边最短路径

又看到大神的另一种思路:used[x][u][v] 来记录对于以x为源点的最短路径树,是否使用w[u][v] 这条路,如果使用则重新计算一遍最短路,这样就能得到正确结果



#include <cstdio>
#include <cstring>

using namespace std;

const int INF=0x3f3f3f3f;
const int MAXN=105;
int w[MAXN][MAXN],dis[MAXN][MAXN],dist[MAXN],num[MAXN][MAXN],sta[3005],des[3005];
int n,m,s,e,u,tmp,sum,ans;
bool vis[MAXN],used[MAXN][MAXN][MAXN];

void Dijkstra() {
    int i,j;
    for(i=1;i<=n;++i) {
        tmp=INF,e=0;
        for(j=1;j<=n;++j)
            if(!vis[j]&&dist[j]<tmp)
                tmp=dist[u=j];
        if(tmp==INF)
            return ;
        vis[u]=true;
        for(j=1;j<=n;++j)
            if(!vis[j]&&(tmp=dist[u]+w[u][j])<dist[j])
                dist[j]=tmp;
    }
}

void DijkstraInit() {
    int i,j;
    for(i=1;i<=n;++i) {
        tmp=INF;
        for(j=1;j<=n;++j)
            if(!vis[j]&&dis[s][j]<tmp)
                tmp=dis[s][u=j];
        if(tmp==INF)
            return ;
        vis[u]=true;
        for(j=1;j<=n;++j)
            if(!vis[j]&&(tmp=dis[s][u]+w[u][j])<dis[s][j]) {
                dis[s][j]=tmp;
                used[s][u][j]=used[s][j][u]=true;
            }
    }
}

void Judge(int i) {
    int j,k;
    for(j=1;j<=n;++j) {
        if(used[j][sta[i]][des[i]]) {
            memset(vis,false,sizeof(vis));
            memset(dist,0x3f,sizeof(dist));
            dist[j]=0;
            Dijkstra();
            for(k=1;k<=n;++k)
                if(dist[k]==INF) {
                    ans=INF;
                    return ;
                }
                else
                    ans+=(dist[k]-dis[j][k])<<1;
        }
    }
}

int main() {
    int i,j;
    while(scanf("%d%d",&n,&m)==2) {
        memset(w,0x3f,sizeof(w));
        memset(dis,0x3f,sizeof(dis));//刚开始忘了初始化dis,结果差不多能跑到最后一组数据,一直以为是算法写错了。。。
        memset(num,0,sizeof(num));
        memset(used,false,sizeof(used));
        for(i=0;i<m;++i) {
            scanf("%d%d",&s,&e);
            dis[sta[i]=s][des[i]=e]=dis[e][s]=w[s][e]=w[e][s]=1;
            ++num[s][e],++num[e][s];//记录边出现的次数
            used[s][s][e]=true;//由于dis[s][e]已经初始化,且权值为1,所以(s,e)一定会出现在以s为源点的最短路径树上
        }
        sum=0;
        for(i=1;i<=n;++i) {
            s=i,dis[i][i]=0;
            memset(vis,false,sizeof(vis));
            DijkstraInit();
            for(j=1;j<i;++j)
                sum+=(dis[i][j]<<1);//根据题意得图是连通的
        }
        for(i=0;i<m;++i) {
            if(num[sta[i]][des[i]]>1)//特判,如果该边出现的次数>1就直接输出结果
                printf("%d\n",sum);
            else {
                w[sta[i]][des[i]]=w[des[i]][sta[i]]=INF;
                ans=sum;
                Judge(i);
                if(ans!=INF)
                    printf("%d\n",ans);
                else
                    printf("INF\n");
                w[sta[i]][des[i]]=w[des[i]][sta[i]]=1;
            }
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值