LA 4080 Warfare A…

这是一个最短路树的题目 ,  这里有一个陷阱 , 有重边 , 如果有重边时必须用第二短的边来代替 。

解法:我们求出一个源点出发的最短路之后 , 我们得到的是一颗树 , 但是这颗树不一定是最小生成树 , 因此如果我们要删除的边在这颗树上 , 那么这个源点出发的最短路径长度就会改变 , 如果不在 , 那么就肯定不会改变,因此我们就只需要判断这条边是否存在这棵树上。

写代码时 , 一定要头脑清醒 , 不能出一点差错 , 不然 , 到后面来找时 , 很难找到
#include
#include
#include
#include
#include
#include
using namespace std;

const int MAXN = 110;
const long long INF = 100000000000000 ;
vectorgrap[MAXN];
long long g[MAXN][MAXN] , g1[MAXN][MAXN];
int n , m , p[MAXN][MAXN] , l = 0;
long long sum1 = 0 , d[MAXN][MAXN];

void init()
{
      for(int i = 1 ; i <= n; i++)
            grap[i].clear();
      memset(g , 0 , sizeof(g));
      memset(g1 , 0 , sizeof(g1));
      memset(p , 0 , sizeof(p));
      sum1 = 0;

}

long long spfa(int s)  // 初始化求所有最短路的和
{
      int i , done[MAXN] ;
      memset(done , 0 , sizeof(done));
      for(i = 1; i <= n; i++)  d[s][i] = INF ;
      d[s][s] = 0;
      queueq ;
      q.push(s);  //  队列记录下点
      while(!q.empty())
      {
            int u = q.front() ; q.pop() ;
            done[u] = 0;
            for(i = 0 ; i < grap[u].size() ; i++)
            {
                  int v = grap[u][i];
                  if(d[s][v] > (d[s][u] + g[u][v]))
                  {
                        d[s][v] = d[s][u] + g[u][v];
                        p[s][v] = u;
                        if(!done[v]) { q.push(v) ;  done[v] = 1; }
                  }
            }
      }
      long long sum = 0;
      for(i = 1; i <= n; i++)
      {
            if(d[s][i] >= INF)  //  如果有某个点是孤立点
                  sum += l;
            else sum += d[s][i] ;


      }
      return sum;
}

long long spfa1(int s)  // 初始化求所有最短路的和
{
      int i , done[MAXN] ;
      long long d1[MAXN] , sum = 0 ;
      memset(done , 0 , sizeof(done));
      for(i = 1; i <= n; i++)  d1[i] = INF ;
      d1[s] = 0;
      queueq ;
      q.push(s);  //  队列记录下点
      while(!q.empty())
      {
            int u = q.front() ; q.pop() ;
            done[u] = 0;
            for(i = 0 ; i < grap[u].size() ; i++)
            {
                  int v = grap[u][i];
                  if(g[u][v] && d1[v] > (d1[u] + g[u][v]))
                  {
                        d1[v] = d1[u] + g[u][v];
                        if(!done[v]) { q.push(v) ;  done[v] = 1; }
                  }
            }
      }
      for(i = 1; i <= n; i++)
      {
            if(d1[i] >= INF)  //  如果有某个点是孤立点 , 那么就直接返回
                  sum += l;
            else sum += d1[i] ;


      }
      return sum;
}

int main()
{
      while(scanf("%d %d %d" , &n , &m , &l) != EOF)
      {
            init();
            int i , j , k , b , x , y;
            long long  dist ;
            for(i = 0 ; i < m ; i++)
            {
                  cin>>x>>y>>dist;
                  if(g[x][y])
                  {
                        if(g[x][y] > dist)
                        {
                              g1[x][y] = g1[y][x] = g[x][y] ;
                              g[x][y] = dist;
                              g[y][x] = dist;
                        }
                        else if(g1[x][y] == 0 || g1[x][y] > dist)  g1[x][y] = g1[y][x] = dist;
                  }
                  else
                  {
                        grap[x].push_back(y);
                        grap[y].push_back(x);
                        g[x][y] = dist;
                        g[y][x] = dist;
                  }
            }
            long long d_sum[MAXN] ;
            for(i = 1; i <= n; i++)
            {
                  d_sum[i] = spfa(i);
                  sum1 += d_sum[i];
            }

            long long max_sum  , sum2 = 0;
            for(i = 1; i <= n  ; i++)
                  for(j = i+1 ; j <= n; j++)
                  {
                        max_sum = sum1 ;// 在这个地方 , wa了很多次 , max_sum的赋值必须放在if的外面。
                        if(g[i][j])
                        {
                              dist = g[i][j]; 
                              if(g1[i][j])
                                    g[i][j] = g[j][i] = g1[i][j] ;
                              else  g[i][j] = g[j][i] = 0;

                              for(k = 1; k <= n; k++)
                              {
                                    for(b = 1; b <= n; b++)
                                          if((p[k][b] == i && b ==j) || (p[k][b] == j && b == i))  break;
                                    if(b <= n)
                                    {
                                          max_sum -= d_sum[k];
                                          max_sum += (long long)spfa1(k);
                                    }
                              }
                              g[i][j] = g[j][i] = dist;

                        }
                        //cout<<max_sum<<endl;
                        if(max_sum > sum2)
                        {

                              sum2 = max_sum;
                        }
                  }
            cout<<sum1<<" "<<sum2<<endl;

      }
      return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值