HDU 2433 Travel

来源:互联网 发布:淘宝联盟怎么得佣金 编辑:程序博客网 时间:2024/06/06 00:26

Travel

Time Limit : 10000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 11   Accepted Submission(s) : 4
点击打开题目链接

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
[bk][bk][bk][bk][bk][bk]The input contains several test cases. [bk][bk][bk][bk][bk][bk]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. [bk][bk][bk][bk][bk][bk]The input will be terminated by EOF.
 

Output
[bk][bk][bk][bk][bk][bk]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 45 11 33 25 42 21 21 2
 

Sample Output
INFINFINFINF22

 

题目意思:

第一行输入两个数字N,M,N是城市个数,M是道路条数,路的长度恒为1,然后接下来给出M条边,这个边是无方向的,即可以通过这条路从城市1

到城市2,也可以从城市2到城市1,依次输出删除第i条边后,图中任意两点最短路径的和值,如果删除第i条边后,有两个城市间不存在最短路径了,就输出INF。

解题思路:

这个题,好心累,看了一下午题解。

1.英文的,题目意思难理解。 2.理解了之后也发现不会写。本来只会Dijstra和Flody两种最短路算法,因为题目中要的是任意两点的最短路径和,则刚开始会想到Flody,但是其本身时间复杂度高,而且这个题目删除一条边后,都要Flody,题目给最多给100个顶点,Flody一次最多100*100*100.题目又最多给出3000条边,删除一条边一次Flody一次,最多3000*100*100*100的时间复杂度,不可能了。因为题目说了任何一边其距离都为1,则可以用广搜。存储图用容器,其实和临界链表存储是一样的。基本思路是还是要先求出每个点到其他点的最短路径和,然后再考虑删除边的影响。

注意下面几点:

1.初始求每个点到其他点的最短路,如果发现某个点到另一个点是没有最短路径的时候,则图自身就不能保证任意两点之间存在最短路径,此时不用再

去考虑删除M条边了。直接输出M个INF就可以了。

2.如果图任意两点间都能求出最短路径,考虑删除第i条边,如果有重复的边,则删除该边后,对答案没有影响,直接输出答案就可以了。

3.如果删除该边i后,某两个顶点间没有直接通路。那么考虑N个顶点,如果顶点t到其他点的最短路用到了这两个顶点,重新求t到其他最短路的值。

这时如果发现t与某一顶点没有最短路径了,则直接输出INF,不用再考虑后面的点了。

看了一下午别人的题解,终于理清思路了,遇到不会的知识尽力去学习就有收获,开心。


#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<cstring>#define INF 0x3f3f3f3f#define MAXN 103using namespace std;int N,M;                    ///N个顶点,M条边struct edge{    int s;                  ///起点    int d;                  ///终点};struct edge E[3002];        ///用来存放边的数组vector<int>node[MAXN];      ///用容器来存放图,相当于临接链表int used[MAXN][MAXN][MAXN]; ///used[x][u][v],以x为源点的广搜树用到了u-v这条边int road[MAXN][MAXN];       ///该数组用来记录u-v路的条数,要知道如果有重边,删除后是没有影响的。int sum[MAXN];              ///sum[i]用来存放以i为源点到其他点最短路径的和int dis[MAXN];              ///用来存放以某个点为源点到其它点的最短路径int vis[MAXN];              ///用来记录标记的数组。int ans;                    ///用于存放答案void GetEdge()              ///获取边信息初始化图的函数{    int i,j,u,v;    for(i = 1; i <= N; i++)    {        node[i].clear();   ///清空节点i所对应的容器        for(j = 1; j <= N;j++)        {            road[i][j] = 0;   ///任意两个顶点之间的路的条数都初始化为0        }    }    for(i = 0; i < M; i++)    ///输入M条边    {        scanf("%d%d",&u,&v);  ///顶点u到顶点v有一条边        E[i].s = u;        E[i].d = v;        ///注意图是无向图        node[u].push_back(v); ///顶点u的后继顶点之一是v        node[v].push_back(u); ///顶点v的后继顶点之一是u        road[u][v]++;       ///u到v的道路条数和v到u的道路条数都增加1        road[v][u]++;    }}int spfa_bfs1(int start) ///该函数求未删除任何边时,某个源点到其他点的最短路{    int i,j,cur,nex;    for(i = 1; i <= N; i++)  ///初始化起点start到其他点的最短路径    {        dis[i] = INF;        vis[i] = 0;    }    dis[start] = 0;         ///标记起点并入队    vis[start] = 1;    queue<int>qu;    qu.push(start);    while(!qu.empty())    {        cur = qu.front();        qu.pop();        vis[cur] = 0;        for(int i = 0; i < node[cur].size(); i++)        {            nex = node[cur][i];            if(dis[cur]+1 < dis[nex])  ///如果start到cur再到nex比start到nex的最短路小            {                dis[nex] = dis[cur]+1;                used[start][cur][nex] = used[start][nex][cur] = 1; ///标记                if(vis[nex] == 0)                {                    vis[nex] = 1;                    qu.push(nex);                }            }        }    }    int temp = 0;    for(i = 1; i <= N; i++)    {        if(dis[i]<INF)            temp = temp + dis[i];        else             ///代表图本身就有两个点不通            return -1;    }    return temp;}int spfa_bfs2(int start)  ///删除某条边后,重新求最短路{    int i,j,cur,nex;    for(i = 1; i <= N; i++)    {        dis[i] = INF;        vis[i] = 0;    }    dis[start] = 0;    vis[start] = 1;    queue<int>qu;    qu.push(start);    while(!qu.empty())    {        cur = qu.front();        qu.pop();        vis[cur] = 0;        for(i = 0; i < node[cur].size(); i++)        {            int nex = node[cur][i];            if(road[cur][nex])   ///因为删除了某条路,需要判断是否有路            {                if(dis[cur]+1 < dis[nex])                {                    dis[nex] = dis[cur]+1;                    if(vis[nex]==0)                    {                        vis[nex] = 1;                        qu.push(nex);                    }                }            }        }    }    int temp = 0;    for(i = 1; i <= N; i++)    {        if(dis[i]<INF)            temp += dis[i];        else  ///说明start到i的最短路为INF,代表没有路径。            return -1;    }    return temp;}int main(){    int i,j,flag,status,t;    while(~scanf("%d%d",&N,&M))    {        memset(used,0,sizeof(used));  ///初始化used数字        flag = 1;   ///flag用来标记题目给的图是否任意两点间都连通,初始时1,代表任意两点间都连通        ans = 0;        GetEdge();  ///获取边        for(i = 1; i <= N; i++)        {            sum[i] = spfa_bfs1(i);            if(sum[i] == -1)  ///代表i到某点无最短路,flag状态改变            {                flag = 0;                break;            }            ans += sum[i];  ///加上第i个点到其他点的最短路径和        }        if(flag)  ///题目数据本身构成的图任意两点之间都有最短路        {            for(i = 0; i < M; i++)  ///用来删除第M条边            {                int a = E[i].s;                int b = E[i].d;   ///删除第i条边                road[a][b]--;                road[b][a]--;                if(road[a][b]>0)  ///顶点a与顶点b之间有重边,删除一条边无影响                {                    printf("%d\n",ans);                }                else ///如果删除一条边a,b之间没有边了                {                    int temp = ans;                    status = 1;                    for(j = 1; j <= N; j++)                    {                        if(used[j][a][b])  ///如果以j为源点用到了边a,b重新求其到其他边的最短路                        {                            temp = temp - sum[j];                            t = spfa_bfs2(j);   ///求删除a,b后,j到其他点新的最短路径和                            if(t == -1)         ///删除一条边a,b后,j到某个点不通了                            {                                printf("INF\n");  ///直接输出INF                                status = 0;                                break;                            }                            temp = temp + t;                        }                    }                    if(status)                        printf("%d\n",temp);                }                road[a][b]++;     ///注意恢复图原来的状态                road[b][a]++;            }        }        else   ///题目所给数据本身不能满足任意两点间存在最短路径,直接输出M个INF        {            for(i = 1; i <= M; i++)                printf("INF\n");        }    }    return 0;}



0 0
原创粉丝点击