HDU 2433 TRAVEL

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

题意:给出边建立图 然后依次删除给出的边,求最短路,如无法连通 则返回INF

这里最短路 =  多源最短路和  即求出对于单源最短路 再for一个循环求出多源最短路  相加

用dijkstra 复杂度为V*(E+V),由于这里很特殊 每条路长度都是1 故可以使用bfs 最先搜到的节点一定是最短的

bfs 时间复杂度 E , 但如果每次拆路都对所有节点重新求最短路 复杂度则是 E*V*E 还多个case 可能不过

这里可以使用used[x][u][v] 来记录对于以x为源点的树 是否使用town[u][v] 这条路 若有,则更新sum[x], 若无 continue

即更新所有有用到被拆路的树。。。 

View Code
/*
这道题最主要是分清哪些是暂时的,哪些存储的是一个case
对于每一个case,used、sum、totalA、town都是不能改变的
对于拆的每一条路 可以暂时改变,如town 但最后还是要恢复
因为拆路只是暂时的 而以上的数组是建路了之后就定下来了
对于vis dis这些只是每次bfs使用的,故不需要保存 只要每次清零即可
*/
#include <stdio.h>
#include <queue>
using namespace std;

const int MAXE = 3005, MAXV = 105;
struct node
{
    int a, b;
}cut[MAXE];
int rn, tn, total, totalA;
int town[101][101], sum[MAXV];
//int vis[101];
bool used[MAXV][MAXV][MAXV];
queue<int> q;

int  vis[MAXV], dis[MAXV];
int bfs(int src, bool mark)
{
    int i;
    while(!q.empty())
        q.pop();
    memset(vis, 0, sizeof(vis));
    memset(dis, 0, sizeof(dis));
    q.push(src);
    vis[src] = 1;
    while(!q.empty())
    {
        int num = q.front();
        q.pop();
        for(i=1; i<=tn; i++)
        {
            if(!vis[i] && (town[num][i]>0 || town[i][num]>0))
            {
                vis[i] = 1;
                if(mark == 0)  // 控制是否改变used
                    {used[src][i][num] = 1; used[src][num][i] = 1;}
                dis[i] += dis[num]+1;
                q.push(i);
            }
        }
    }
    int tot = 0;
    for(i=1; i<=tn; i++)
    {
        if(!dis[i] && i != src)
            return -1;
        tot += dis[i];
    }
    return tot;
}

int main()
{
    int i, j;
    int a, b;
    while(~scanf("%d %d", &tn, &rn))
    {
        totalA = 0;
        memset(town, 0, sizeof(town));
        memset(sum, 0, sizeof(sum));
        memset(used, 0, sizeof(used));
        for(i=1; i<=rn; i++)
        {
            scanf("%d %d", &a, &b);
            cut[i].a = a, cut[i].b = b;
            town[a][b] ++;
            town[b][a] ++;
        }
        for(i=1; i<=tn; i++)
        {
            sum[i] = bfs(i, 0);
            if(sum[i] == -1)  // 注意本来是否有不可达的点  有则无论有没拆路都是INF 直接返回
            {    totalA = -1; break; } 
            else
                totalA += sum[i];
        }

        for(i=1; i<=rn; i++)
        {
            total = totalA ;  // 使用一个临时代替不能改变的
            town[cut[i].a][cut[i].b] --;
            town[cut[i].b][cut[i].a] --;
            if(town[cut[i].a][cut[i].b]>0 )
                printf("%d\n", total);
            else if( total == -1 )
                printf("INF\n");
            else
            {
                bool f = 0;
                for(j=1; j<=tn; j++)
                    if(used[j][cut[i].a][cut[i].b] == 1)
                    {
                        total -= sum[j];
                        int tmp = bfs(j, 1);  // 不能把bfs()直接赋给sum[x] 因为拆路只是暂时的
                        if(tmp == -1)
                        { f = 1; break;}
                        total += tmp;
                    }
                if(f)
                    printf("INF\n");
                else 
                    printf("%d\n", total);
            }
            town[cut[i].a][cut[i].b] ++;
            town[cut[i].b][cut[i].a] ++;

        }

    }
    return 0;
}

 

posted @ 2013-03-10 10:13  April_Tsui  阅读(948)  评论(0编辑  收藏  举报