牛客多校第四场 J Free 最短路

题意:

求最短路,但是你有k次机会可以把路径中某条边的长度变为0.

题解:

跑k+1次迪杰斯特拉,设想有k+1组dis数组和优先队列,第k组就意味着删去k条边的情况,每次松弛操作,松弛的两点i,j和距离l(i,j),不仅更新本组的dis数组令dis[j]=dis[i]+l[i,j],还更新下一组,令dis`[j]=dis[i],相当于删去边(i,j)

#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#define INF 0x3f3f3f3f
struct Point{
    int n,dis;
    friend bool operator >(const Point &a,const Point &b){
        return a.dis>b.dis;
    }
    friend bool operator <(const Point &a,const Point &b){
        return a.dis<b.dis;
    }
    Point(){}
    Point(int a,int b){
        n=a;dis=b;
    }
};
using namespace std;
int lik[1003][1003];
int dis[1003][1003];//删去了i条边后第j个点最短距离
priority_queue<Point,vector<Point>,greater<Point> > que[1003];
vector<Point>link[1003];
int main(){
    int n,m,s,t,k;
    scanf("%d %d %d %d %d",&n,&m,&s,&t,&k);
     
    memset(dis,INF,sizeof dis);
    memset(lik,INF,sizeof lik);
    for(int i=1;i<=m;i++){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        if(a==b)continue;
        else{
            lik[a][b]=min(lik[a][b],c);
            lik[b][a]=min(lik[b][a],c);
        }
    }
     
//  for(int i=1;i<=n;i++){
//      for(int j=1;j<=n;j++){
//          printf("%d ",lik[i][j]);
//      }
//      printf("\n");
//  }
     
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            if(lik[i][j]<INF){
                link[i].push_back(Point(j,lik[i][j]));
                link[j].push_back(Point(i,lik[j][i]));
            }
             
        }
    }
     
//  for(int i=1;i<=n;i++)printf("%d ",link[i].size());
     
//  system("pause");
    que[0].push(Point(s,0));
    dis[0][s]=0;
     
    for(int i=0;i<=k;i++){
        while(!que[i].empty()){
             
            Point tmp=que[i].top();
            que[i].pop();
            int u=tmp.n;
            int nowd=tmp.dis;
            if(nowd>dis[i][u])continue;
             
//          printf("*%d %d\n",u,nowd);
             
            for(int j=0;j<link[u].size();j++){
                int v=link[u][j].n;
                int d=link[u][j].dis;
                 
                if(dis[i][v]>nowd+d){
                    dis[i][v]=nowd+d;
                    que[i].push(Point(v,dis[i][v]));
                }
                 
                if(i<k && dis[i+1][v]>nowd){
                    dis[i+1][v]=nowd;
                    que[i+1].push(Point(v,dis[i+1][v]));
                }
                 
//              for(int w=0;w<=k;w++){
//                  for(int r=1;r<=n;r++){
//                      printf("%d ",dis[w][r]);
//                  }
//                  printf("\n");
//              }
//              printf("\n");
                 
            }
             
        }
    }
//  for(int w=0;w<=k;w++){
//      for(int r=1;r<=n;r++){
//          printf("%d ",dis[w][r]);
//      }
//      printf("\n");
//  }
    int minn=INF;
    for(int i=0;i<=k;i++){
        minn=min(minn,dis[i][t]);
    }
    printf("%d\n",minn);
}

猜你喜欢

转载自www.cnblogs.com/isakovsky/p/11257352.html