• 单源最短路(spfa),删边求和


    http://acm.hdu.edu.cn/showproblem.php?pid=2433

    Travel

    Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 1572    Accepted Submission(s): 526


    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
     
    题意:

    因为每次只删除一条边,所以删除边后的sum,其实就与这条边上有关,或者所是和这条边上的两个端点有关,
    首先 每次删除边都计算一次的暴力做法是不可能ac的, 除了用什么优化,但是也是很慢的。
    所以只能在每次删除边的时候,做一些改变。
    具体的做法是:
    对每一个点求一次最短路,并将其求和,保存在一个数组里头,定为sum[i],i表示着一个点到所有其他点最短路之和。并将这些和相加 ans = sum[1]  + …… + sum[n]; 
          然后,删除一条边,其顶点暂定为u,v,对这条边的一个顶点u在一次求最短路,如果这个点,不能到达这条边的另一个点v,则 直接输出INF
          如果,能够到达,则对v也求一次最短路,对于u,v两点来说,求得u到每一个点的最短路之和sum_u,求得v到每一个点的最短路之和sum_v,
          最后结果为: ans = ans + sum_u + sum_v - sum[u] - sum[v];
    程序:
    #include"stdio.h"
    #include"string.h"
    #include"queue"
    #include"iostream"
    #define inf 10000
    #define M 111
    using namespace std;
    int n,dis[M],use[M];
    struct st
    {
        int u,v,w,next;
    }edge[M*M];
    int head[M],t;
    void init()
    {
        t=0;
        memset(head,-1,sizeof(head));
    }
    void add(int u,int v,int w)
    {
        edge[t].u=u;
        edge[t].v=v;
        edge[t].w=w;
        edge[t].next=head[u];
        head[u]=t++;
    }
    void spfa(int s)
    {
        int i;
        queue<int>q;
        memset(use,0,sizeof(use));
        for(i=1;i<=n;i++)
            dis[i]=inf;
        dis[s]=0;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            use[u]=0;
            for(i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v;
                if(dis[v]>dis[u]+edge[i].w)
                {
                    dis[v]=dis[u]+edge[i].w;
                    if(!use[v])
                    {
                        use[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    int x[3009],y[3009],sum[M];
    int main()
    {
        int m,i,j,sum_v,sum_u;
        while(scanf("%d%d",&n,&m)!=-1)
        {
            init();
            for(i=1;i<=m;i++)
            {
                scanf("%d%d",&x[i],&y[i]);
                add(x[i],y[i],1);
                add(y[i],x[i],1);
            }
            int ans=0;
            for(i=1;i<=n;i++)
            {
                sum[i]=0;
                spfa(i);
                for(j=1;j<=n;j++)
                    sum[i]+=dis[j];
                ans+=sum[i];
            }
            for(i=1;i<=m;i++)
            {
                edge[i*2-1].w=edge[i*2-2].w=inf;
                spfa(x[i]);
                sum_u=0;
                for(j=1;j<=n;j++)
                    sum_u+=dis[j];
                if(sum_u>=inf)
                {
                    edge[i*2-1].w=edge[i*2-2].w=1;
                    printf("INF
    ");
                    continue;
                }
                sum_v=0;
                spfa(y[i]);
                for(j=1;j<=n;j++)
                    sum_v+=dis[j];
                printf("%d
    ",ans+sum_u+sum_v-sum[x[i]]-sum[y[i]]);
                edge[i*2-1].w=edge[i*2-2].w=1;
            }
        }
    }
    



  • 相关阅读:
    Action获取表单数据的三种方式
    Action三种编写方式
    hibernate 查询方式
    hibernate 多对多操作(级联操作)
    对拍
    树的数据生成器
    SPOJ1825 Free tour II 树分治
    Codeforces 474(#271 Div 2) 解题报告
    HNCPC2012 总结
    Sort 对下标进行排序
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348218.html
Copyright © 2020-2023  润新知