CCF 交通规划

题意大致如下:给你一张无向带权图,有标号为1到n的节点,现在要你选择一些边留下来,使得在留下来的边构成的新的图里,每个节点到节点1的最小距离不变(即和初始图一样),在满足上述要求的前提下,要使留下来的边的权重和最小,并求出这个最小权重和。

题解:只要我们用dijsktra算法加以改造遍历一遍原图,就能解决这个问题。而本题与一般的dijsktra模板题不同的地方在于,一般dijsktra只是求出源点到其他个点的最短距离,但并不考虑和记录路径,但本题要求的是权重和的最小值,也就是说我们要知道的是最后我们选择了哪些边留下来,或者说我们要知道留下来的所有边的权重是多少。为此,我建立了一个结构体叫Node,它有成员dist和cost,dist是表示它到源点的最小距离,而cost是表示为了使它和源点联通的最小花费(这个联通要保证是最短距离的前提下)。至于更新,dist更新和正常dijsktra更新时一样,先找到一个目前没有被加入集合的dist最小的节点u,然后用u来更新周边节点的dist,cost更新则是随着dist的更新进行的(如此保证这个cost满足最小距离这个前提),并且这个cost应该就等于节点u和被更新节点v的边的权重,即有Node[v].cost=weight[u][v]。最后,要注意的就是,有些节点的最短路径可能不止一条,而且,这些节点被开始的u节点更新得到的cost会要比后面的u节点更新得到的cost要大,所以当有Node[v].dist==Node[u].dist+weight[u][v]时,要注意更新Node[v].cost。(根据题目范围,dijkstra算法应用优先队列进行优化)

输入: 两个整数n,m。n是节点数,m是边数。就下来m行,每行三个数u,v,w,代表节点u,v之间有一条权重为w的边。

输出:一个整数,最小权重和。

代码如下:

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=10100;
const int maxm=101010;
const int inf=0x08080808;
int n,m;
int head[maxn],icount,vis[maxn];
struct Edge{
    int v,w;
    int next;
}edge[maxm*2];
struct Node{
   int dist;
   int cost;
}node[maxn];
struct Dist{
    int dist;
    int num;
    bool operator <(const Dist& a)const {
        return dist>a.dist;
    }
};
priority_queue pq;
void insert_edge(int u,int v,int w){
    edge[icount].v=v;
    edge[icount].w=w;
    edge[icount].next=head[u];
    head[u]=icount++;
}

void Dij(int s){
    for(int i=1;i<=n;++i){
        node[i].dist=node[i].cost=inf;
        vis[i]=0;
    }
    Dist temp={0,s};
    node[s].dist=node[s].cost=0;
    pq.push(temp);
    for(int i=1;i

你可能感兴趣的:(CCF)