HDU 2433 最短路

来源:互联网 发布:维多利亚贝克汉姆知乎 编辑:程序博客网 时间:2024/05/01 17:18
////这道题是一道很巧妙的最短路。题目大致的意思就是给定一张无向图,枚举每条边删去,求剩下的图中每个////点对距离之和。//////2433  Travel  删边+最短路之和(预处理桥边)★★★//////注意处理重边//这道题目标程的关键在于两点,第一点在于把所有的最近点对拆分成n个顶点到剩余点的n棵最短路径树,//这样子把整体的不容易去表示的拆分成n个点去跑最短路,使得简化,//这样这道题目就已经简化成了通过某一个顶点枚举删去一条边,求剩下的最短路之和,第二点就是在不必每删去//一条求一次最短路,求出求出最短路径树之后有n-1条边存在于树上,删去其他的边没有影响。这个问题就拆分成//了预处理n棵最短路径树,总共存在n*n-1边 然后跑这么多次最短路,复杂度降为了 n*n*m.//总结一下,将一个整体分拆成一些部分,对每个部分先进行预处理。这样通过枚举最短路径树上的边,这样//子就大大减少了重复计算的次数。对最短路的理解还不够透彻。//标程算法:仍然使用上面的思路,但要作一些预处理。对每个顶点u求一次单源最短路,把求得的结果称作u的最//短路径树,并用数组记录所有点到 其他所有顶点的路径的和。若被破坏的公路不在该最短路径树上,则从u出发//的所有最短路径的总和就是u到该树上的所有顶点的路径的总和,因为刚刚记录了这个 数值,因此花费O(1)时间//就能返回结果。否则,删除被破坏的公路后,//重新通过BFS计算从u出发的所有最短路径的总和,//还要判断被破坏的公路在不在这条最短路径树上。//所以只能在每次删除边的时候,做一些改变。//具体的做法是://对每一个点求一次最短路,并将其求和,保存在一个数组里头,定为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<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#include<queue>#define maxn 200#define maxm 8000#define inf 80000using namespace std;//去掉桥边的处理就对了,好像是我桥边处理的问题。int g[maxn][maxn];bool vis[maxn];int head[maxn],low[maxn];int n,m,cnt,time;bool flag[maxn][maxn][maxn];///i,u,v;点i用到边u,v;struct Edge{ int from,to,next; bool sign;}edge[2*maxm];void addedge(int a,int b){    edge[cnt].from=a;    edge[cnt].to=b;    edge[cnt].next=head[a];    head[a]=cnt++;    edge[cnt].sign=false;}void dfs(int u,int fa){    vis[u]=true;    low[u]=time++;    for(int i=head[u];~i;i=edge[i].next)    {        int v=edge[i].to;        if(v==fa) continue;        if(!vis[v]) dfs(v,u);        low[u]=min(low[u],low[v]);    }}void  tarjan(){  time=0;  memset(low,-1,sizeof(low));  dfs(1,1);}int cost[maxn][maxn];int d[maxn];bool used[maxn];int tree[maxn];int  spfa( int s )//用处理单源最短路径,但是还要记录用上的边。{  int i,now;  for( i=1;i<=n;++i )  {    d[i]=inf;    used[i]=false;  }  d[s]=0;  queue <int> q;  q.push(s);  used[s] = true;  while(!q.empty())  {    now = q.front();    q.pop();    used[now] = false;    for(i = 1; i <= n; i++)    {      if(d[i] > d[now] + cost[now][i])///这里的话算是用上这条边了么。。。      {        flag[s][now][i]=true;        d[i] = d[now] + cost[now][i];        if(used[i] == 0)        {          q.push(i);          used[i] = true;        }      }    }  }   int all=0;   for(int i=1;i<=n;i++)    all+=d[i];   return all;}int  spfa2( int s )//用处理单源最短路径,但是还要记录用上的边。{  int i,now;  for( i=1;i<=n;++i )  {    d[i]=inf;    used[i]=false;  }  d[s]=0;  queue <int> q;  q.push(s);  used[s] = true;  while(!q.empty())  {    now = q.front();    q.pop();    used[now] = false;    for(i = 1; i <= n; i++)    {      if(d[i] > d[now] + cost[now][i])///这里的话算是用上这条边了么。。。      {        d[i] = d[now] + cost[now][i];        if(used[i] == 0)        {          q.push(i);          used[i] = true;        }      }    }  }   int all=0;   for(int i=1;i<=n;i++)    all+=d[i];   return all;}struct node{    int u,v;}E[maxm];bool ans[maxm];bool index[maxm];void init(){    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)        cost[i][j]=inf;    for(int i=1;i<=n;i++)        cost[i][i]=0;}void build(){    for(int i=1;i<=m;i++)    {        int x=E[i].u;        int y=E[i].v;         cost[x][y]=cost[y][x]=1;    }}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        init();        memset(flag,false,sizeof(flag));        memset(head,-1,sizeof(head));        memset(vis,false,sizeof(vis));        cnt=0;        memset(index,false,sizeof(index));        memset(g,0,sizeof(g));        int tempa,tempb;        for(int i=1;i<=m;i++)        {            scanf("%d%d",&tempa,&tempb);            g[tempa][tempb]++;            g[tempb][tempa]++;            addedge(tempa,tempb);            addedge(tempb,tempa);            cost[tempa][tempb]=cost[tempb][tempa]=1;            E[i].u=tempa;            E[i].v=tempb;        }        for(int i=1;i<=m;i++)        {            int x=E[i].u;            int y=E[i].v;            if(g[x][y]>1)                index[i]=true;        }        int weight=0;        for(int i=1;i<=n;i++)        {           tree[i]=spfa(i);           weight+=tree[i];        }        if(weight>=inf)        {            for(int i=1;i<=m;i++)                puts("INF");            continue;        }        tarjan();        for(int i=0;i<cnt;i++)        {            int x=edge[i].from;            int y=edge[i].to;            if(low[x]!=low[y])                edge[i].sign=true;        }        memset(ans,false,sizeof(ans));        for(int i=0;i<cnt;i++)        {            if(edge[i].sign)            {                int temp=i/2+1;                if(!index[temp])                    ans[temp]=true;            }        }         for(int i=1;i<=m;i++)        {//            if(ans[i])//桥的处理去掉就过了,应该是桥的处理的问题。//             {//                   puts("INF");continue;//             }             if(index[i])             {                 printf("%d\n",weight); continue;             }            int x=E[i].u;            int y=E[i].v;            init();            build();            cost[x][y]=cost[y][x]=inf;///建边            int rees=0;            for(int j=1;j<=n;j++)            {                if(flag[j][x][y]||flag[j][y][x])                {                    int temp=spfa2(j);                    rees+=temp;                }                else                    rees+=tree[j];            }            if(rees>=inf)               puts("INF");            else               printf("%d\n",rees);        }    }}

0 0
原创粉丝点击