HDU 2433 Travel (单源最短路SSSP,BFS,变形)

 

 

 

题意:给出一个图的所有边,每次从图中删除一条边,求所有顶点对的路径总和(求完了就将边给补回去)。(同一条边可能给多次)

思路:边数是3000,定点是100。那么m条边就需要计算m次,每次要计算整个图中的所有顶点对的距离O(n2)。这样算起来3000*100*100也只是3千万而已,没错,居然超时了,说明数据有很多,估计是有100个以上的极限数据,也就是30亿。

 

 

 

 

  1 #include <bits/stdc++.h>

  2 using namespace std;

  3 const int N=105, INF=0x7f7f7f7f;

  4 int mapp[N][N];

  5 bool vis[N];     //是否存在队列中

  6 int dest[N];

  7 vector<pair<int,int> >  vect;

  8 int n, m;

  9 int num[N];

 10 

 11 

 12 void spfa(int x)

 13 {

 14     memset(vis,0,sizeof(vis));

 15     memset(dest,0x7f,sizeof(dest));

 16     deque<int> que;

 17     que.push_back(x);

 18     vis[x]=1;

 19     dest[x]=0;

 20     while(!que.empty())

 21     {

 22         int tmp=que.front();

 23         que.pop_front();

 24         vis[tmp]=0;

 25         for(int i=1; i<=n; i++)

 26         {

 27             if(mapp[tmp][i]>0 && dest[tmp]+1<dest[i] )

 28             {

 29                 dest[i]=dest[tmp]+1;

 30                 if(!vis[i]) //没有在队列中

 31                 {

 32                     vis[i]=1;

 33                     //que.push_back(i);

 34                     if(!que.empty() && dest[i]<dest[que.front()])    que.push_front(i);

 35                     else    que.push_back(i);

 36                 }

 37             }

 38         }

 39     }

 40 }

 41 

 42 

 43 

 44 

 45 int cal()

 46 {

 47     int sum=0;

 48     for(int i=1; i<=n; i++)

 49     {

 50 

 51         spfa(i);

 52         for(int j=1; j<=n; j++)

 53         {

 54             if(dest[j]==INF)    return 0;

 55             sum+=dest[j];

 56         }

 57     }

 58     return sum;

 59 }

 60 

 61 

 62 

 63 

 64 

 65 int main()

 66 {

 67     freopen("input.txt", "r", stdin);

 68     int a, b, c;

 69     while(~scanf("%d%d", &n, &m))

 70     {

 71         vect.clear();

 72         memset(mapp,0,sizeof(mapp));

 73         memset(num,0,sizeof(num));

 74         for(int i=0; i<m; i++)

 75         {

 76             scanf("%d%d",&a,&b);

 77             mapp[a][b]++;

 78             mapp[b][a]++;

 79             num[a]++;

 80             num[b]++;

 81             vect.push_back(make_pair(a,b));

 82         }

 83 

 84         for(int i=0; i<vect.size(); i++)

 85         {

 86             a=vect[i].first;

 87             b=vect[i].second;

 88             if(num[a]==1||num[b]==1)

 89             {

 90                 printf("INF\n");

 91                 continue;

 92             }

 93             mapp[a][b]--;    //先断开

 94             mapp[b][a]--;

 95 

 96             int ans=cal();

 97             if(ans==0)  printf("INF\n");

 98             else        printf("%d\n",ans);

 99 

100             mapp[a][b]++;     //再连上

101             mapp[b][a]++;

102         }

103 

104 

105     }

106 

107     return 0;

108 }
正确而TLE代码,spfa+暴力

 

  1 #include <bits/stdc++.h>

  2 using namespace std;

  3 const int N=105, INF=0x7f7f7f7f;

  4 int mapp[N][N];//图矩阵

  5 bool mapp2[N][N][N];   //标记从某点出发所需关键路径

  6 int tem_sum[N];

  7 int num[N];     //每个点的度

  8 int vis[N];     //用于BFS

  9 vector<pair<int,int> >  vect;   //m条边

 10 int n, m;

 11 

 12 int bfs(int x)

 13 {

 14     memset(vis,0,sizeof(vis));

 15     deque<int> que(1,x);

 16     int cnt=0, sum=0;

 17     vis[x]=1;

 18     while(!que.empty())

 19     {

 20         cnt++;

 21         int siz=que.size();

 22         for(int i=0; i<siz; i++)

 23         {

 24             int tmp=que.front();

 25             que.pop_front();

 26             for(int j=1; j<=n; j++)

 27             {

 28                 if(!vis[j]&&mapp[tmp][j])

 29                 {

 30                     vis[j]=1;

 31                     sum+=cnt;

 32                     mapp2[x][tmp][j]= mapp2[x][j][tmp]=1;//主要在这,记录每个点出发所需要的关键路径

 33                     que.push_back(j);

 34                 }

 35             }

 36         }

 37     }

 38     return sum;

 39 }

 40 

 41 int cal(int a,int b)    //a-b是删除的边

 42 {

 43     int sum=0;

 44     for(int i=1; i<=n; i++)

 45     {

 46         if(!a || mapp2[i][a][b] )

 47         {

 48             int tmp=bfs(i);

 49             if(!tmp)    return 0;

 50             if(!a)  tem_sum[i]=tmp; //第一次求还得更新tem_sum

 51             sum+=tmp;

 52         }

 53         else    sum+=tem_sum[i];

 54     }

 55     return sum;

 56 }

 57 

 58 

 59 

 60 int main()

 61 {

 62     //freopen("input.txt", "r", stdin);

 63     int a, b, c;

 64     while(cin>>n>>m)

 65     {

 66         vect.clear();

 67         memset(mapp,0,sizeof(mapp));

 68         memset(mapp2,0,sizeof(mapp2));

 69         memset(num,0,sizeof(num));

 70         memset(tem_sum,0,sizeof(tem_sum));  //一旦更新,不再改

 71 

 72         for(int i=0; i<m; i++)

 73         {

 74             scanf("%d%d",&a,&b);

 75             mapp[a][b]++, mapp[b][a]++;

 76             num[a]++, num[b]++;

 77             vect.push_back(make_pair(a,b));

 78         }

 79 

 80         int sum=cal(0,0);    //先求sum,看能否每点互通,不通以下都不必计算了。

 81         for(int i=0; i<m; i++)

 82         {

 83             a=vect[i].first,  b=vect[i].second;

 84             if(num[a]==1 || num[b]==1 || m<n || sum==0 )   //度为1的点,边不够,不连通

 85             {

 86                 printf("INF\n");

 87                 continue;

 88             }

 89             if(mapp[a][b]==1)                   //仅有那么1条边,才需要更新

 90             {

 91                 mapp[a][b]--, mapp[b][a]--;     //先断开

 92                 int ans=cal(a,b);//只求需要该边的SSSP

 93                 if(ans==0)  printf("INF\n");

 94                 else        printf("%d\n",ans);

 95                 mapp[a][b]++, mapp[b][a]++;     //再连上

 96             }

 97             else    printf("%d\n",sum);         //非关键,直接输出

 98         }

 99 

100     }

101     return 0;

102 }
AC代码(BFS)

 

你可能感兴趣的:(HDU)