挑战程序设计竞赛 算法和数据结构 第13章 加权图

挑战程序设计竞赛 算法和数据结构 第13章 加权图

13.2 最小生成树

ALDS1_12_A:Minimum Spanning Tree

原书AC代码:

//ALDS1_12_A:Minimum Spanning Tree
#include <iostream>
using namespace std;
static const int MAX=100;
static const int INFTY=(1<<21);
static const int WHITE=0;
static const int GRAY=1;
static const int BLACK=2;
int n,M[MAX][MAX];
int prim(){
    int u,minv;
    int d[MAX],p[MAX],color[MAX];
    for(int i=0;i<n;i++){
        d[i]=INFTY;
        p[i]=-1;
        color[i]=WHITE;
    }
    d[0]=0;
    while(1){
        minv=INFTY;
        u=-1;
        for(int i=0;i<n;i++){
            if(minv>d[i]&&color[i]!=BLACK){
                u=i;
                minv=d[i];
            }
        }
        if(u==-1)break;
        color[u]=BLACK;
        for(int v=0;v<n;v++){
            if(color[v]!=BLACK&&M[u][v]!=INFTY){
                if(d[v]>M[u][v]){
                    d[v]=M[u][v];
                    p[v]=u;
                    color[v]=GRAY;
                }
            }
        }
    }
    int sum=0;
    for(int i=0;i<n;i++){
        if(p[i]!=-1)sum+=M[i][p[i]];
    }
    return sum;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            int e;cin>>e;
            M[i][j]=(e==-1)?INFTY:e;
        }
    }
    cout<<prim()<<endl;
    return 0;
}


参考上述代码,同时也翻看本人以前的编码,本人编写的C语言AC代码如下:

//ALDS1_12_A:Minimum Spanning Tree
//样例通过,提交AC 2017-10-3 18:08
#include <stdio.h>
#include <string.h>
#define INF 999999
int e[110][110],d[110],vis[110];//d[i]  i点到生成树的最短距离
int n;
int min_pos(){
    int i,min=INF,j;
    for(i=1;i<=n;i++)
        if(vis[i]==0&&d[i]<min){
            min=d[i];
            j=i;
        }
    return j;
}
int prim(){
    int sum=0,i,j,k,count=1;
    d[1]=0;
    for(i=2;i<=n;i++)从顶点1开始
        d[i]=e[1][i];
    while(count<=n-1){
        j=min_pos();
        vis[j]=1;
        for(i=1;i<=n;i++)
            if(vis[i]==0&&d[i]>e[j][i])
                d[i]=e[j][i];
        count++;
    }
    for(i=1;i<=n;i++)
        sum+=d[i];
    return sum;
}
int main(){
    int i,j,w;
    memset(e,0,sizeof(e));
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for(i=1;i<=n;i++)//无向图,读取数据
        for(j=1;j<=n;j++){
            scanf("%d",&w);
            if(i!=j){
                if(w==-1)
                    e[i][j]=INF,e[j][i]=INF;
                else
                    e[i][j]=w,e[j][i]=w;
            }
        }
    printf("%d\n",prim());
    return 0;
}



13.3 单源最短路径

ALDS1_12_B:Single Source Shortest Path I

原书AC代码:

//ALDS1_12_B:Single Source Shortest Path I
//C++
#include <iostream>
using namespace std;
static const int MAX=100;
static const int INFTY=(1<<21);
static const int WHITE=0;
static const int GRAY=1;
static const int BLACK=2;
int n,M[MAX][MAX];
void dijkstra(){
    int minv;
    int d[MAX],color[MAX];
    for(int i=0;i<n;i++){
        d[i]=INFTY;
        color[i]=WHITE;
    }
    d[0]=0;
    color[0]=GRAY;
    while(1){
        minv=INFTY;
        int u=-1;
        for(int i=0;i<n;i++){
            if(minv>d[i]&&color[i]!=BLACK){
                u=i;
                minv=d[i];
            }
        }
        if(u==-1)break;
        color[u]=BLACK;
        for(int v=0;v<n;v++){
            if(color[v]!=BLACK&&M[u][v]!=INFTY){
                if(d[v]>d[u]+M[u][v]){
                    d[v]=d[u]+M[u][v];
                    color[v]=GRAY;
                }
            }
        }
    }
    for(int i=0;i<n;i++){
        cout<<i<<" "<<(d[i]==INFTY?-1:d[i])<<endl;
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            M[i][j]=INFTY;
        }
    }
    int k,c,u,v;
    for(int i=0;i<n;i++){
        cin>>u>>k;
        for(int j=0;j<k;j++){
            cin>>v>>c;
            M[u][v]=c;
        }
    }
    dijkstra();
    return 0;
}


未参考上述代码,本人按自己的理解编写的C语言AC代码如下:

//ALDS1_12_B:Single Source Shortest Path I
//采用邻接表方式的迪杰斯特拉算法,样例很快通过,提交AC 2017-10-3 21:13
#include <stdio.h>
#include <string.h>
#define INF 999999999
int e[110][110],vis[110],d[110],n;
int min_pos(){
    int i,min=INF,j;
    for(i=0;i<=n-1;i++)
        if(vis[i]==0&&d[i]<min){
            min=d[i];
            j=i;
        }
    return j;
}
void dijstra(){
    int i,j,count=1;
    vis[0]=1;
    for(i=0;i<=n-1;i++)
        d[i]=e[0][i];
    while(count<=n-1){//剩下n-1个点
        j=min_pos();
        vis[j]=1;
        for(i=0;i<=n-1;i++)
            if(vis[i]==0&&d[i]>d[j]+e[j][i])
                d[i]=d[j]+e[j][i];
        count++;
    }
}
int main(){
    int u,k,v,c,i,j;
    memset(e,0,sizeof(e));
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for(i=0;i<=n-1;i++)
        for(j=0;j<=n-1;j++)
            if(i==j) e[i][j]=0;
            else e[i][j]=INF;
    for(i=1;i<=n;i++){
        scanf("%d%d",&u,&k);
        for(j=1;j<=k;j++){
            scanf("%d%d",&v,&c);
            e[u][v]=c;
        }
    }
    dijstra();
    for(i=0;i<=n-1;i++)
        printf("%d %d\n",i,d[i]);
    return 0;
}


ALDS1_12_C:Single Source Shortest Path II

原书AC代码:

//ALDS1_12_C:Single_Source_Shortest Path II
//C++
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
static const int MAX=10000;
static const int INFTY=(1<<20);
static const int WHITE=0;
static const int GRAY=1;
static const int BLACK=2;
int n;
vector<pair<int,int> >adj[MAX];//加权有向图的邻接表表示法
void dijkstra(){
    priority_queue<pair<int,int> > PQ;
    int color[MAX];
    int d[MAX];
    for(int i=0;i<n;i++){
        d[i]=INFTY;
        color[i]=WHITE;
    }
    d[0]=0;
    PQ.push(make_pair(0,0));
    color[0]=GRAY;
    while(!PQ.empty()){
        pair<int,int> f=PQ.top();PQ.pop();
        int u=f.second;
        color[u]=BLACK;
        //取出最小值,如果不是最短路径则忽略
        if(d[u]<f.first*(-1))continue;
        for(int j=0;j<adj[u].size();j++){
            int v=adj[u][j].first;
            if(color[v]==BLACK)continue;
            if(d[v]>d[u]+adj[u][j].second){
                d[v]=d[u]+adj[u][j].second;
                //priority_queue priority_queue 默认优先最大值,因此要乘以-1.
                PQ.push(make_pair(d[v]*(-1),v));
                color[v]=GRAY;
            }
        }
    }
    for(int i=0;i<n;i++){
        cout<<i<<" "<<(d[i]==INFTY?-1:d[i])<<endl;
    }
}
int main(){
    int k,u,v,c;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>u>>k;
        for(int j=0;j<k;j++){
            cin>>v>>c;//1 此处写成cin>>v>>v; 查了会
            adj[u].push_back(make_pair(v,c));
        }
    }
    dijkstra();
    return 0;
}


仿照上述代码,本人编写的C++语言AC代码如下:

//ALDS1_12_C:Single_Source_Shortest Path II
//样例通过,提交Compile Error,添加头文件 #include <cstdio>,提交AC 2017-10-4 16:06
#include <cstdio>
#include <queue>
#include <cstring>
#define INF 999999999
using namespace std;
vector<pair<int,int> > a[10100];//a相当于二维数组,a[i][j] 里面的数据类型是 整数对 pair<int,int>
int n,d[10100],vis[10100];
void dijkstra(){
    int u,v,i,j;
    priority_queue<pair<int,int> > pq;
    pq.push(make_pair(0,0));//1 请注意不是 pq.push_back(make_pair(0,0));
    for(i=0;i<n;i++)
        d[i]=INF;
    d[0]=0;
    while(!pq.empty()){
        u=pq.top().second;
        pq.pop();
        if(vis[u]==1)continue;//已经访问过
        vis[u]=1;
        for(j=0;j<a[u].size();j++){
            v=a[u][j].second;
            if(vis[v]==0&&d[v]>d[u]+a[u][j].first){//2 此处写成 if(vis[v]==0&&d[u]>d[v]+a[u][j].first)
                d[v]=d[u]+a[u][j].first;//2 此处写成 d[u]=d[v]+a[u][j].first;
                pq.push(make_pair(d[v]*(-1),v));//2 此处写成  pq.push(make_pair(d[u]*(-1),v)); 1 请注意不是 pq.push_back(make_pair(d[u]*(-1),v));
            }
        }
    }
    for(i=0;i<n;i++)
        printf("%d %d\n",i,d[i]);
}
int main(){
    int u,k,v,c,i,j;
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d%d",&u,&k);
        for(j=1;j<=k;j++){
            scanf("%d%d",&v,&c);
            a[u].push_back(make_pair(c,v));//邻接表;先放权重,再放连接的点,这样与 优先队列的数据一致  
        }
    }
    dijkstra();
    return 0;
}

一切都自己写,重写该道题

//ALDS1_12_C:Single_Source_Shortest Path II
//准备采用C语言来编写该题,邻接表,自己写;堆自己写,最小堆
//样例很快通过,提交AC 2017-10-4 17:06
#include <stdio.h>
#include <string.h>
#define INF 999999999
struct node{
    int to,c,next;
}e[500100];//有向图
struct node2{
    int c,v;//c权重,v点
}heap[10000*10];//堆中会有冗余元素,故扩大10倍
int cnt=0,head[10100],n,s=0,vis[10100],d[10100];//  s用来标记堆的最后一个元素
void addedge(int u,int v,int c){
    cnt++,e[cnt].to=v,e[cnt].c=c,e[cnt].next=head[u],head[u]=cnt;
}
//堆操作 最小堆
void push(struct node2 a){//将元素插入堆 最小堆
    int p;//堆中位置
    s++;
    p=s;
    while(p>1&&a.c<heap[p/2].c){//翻看了以前堆的写法,才写出,看来模板就是模板,需要常写常记
        heap[p]=heap[p/2];
        p/=2;
    }
    heap[p]=a;
}
void adjust(int t){//翻看了以前堆的写法
    int left=2*t,right=2*t+1,k=t;
    struct node2 b;
    if(left<=s)k=heap[k].c<heap[left].c?k:left;//找出left right k中对应的heap[].c最小值
    if(right<=s)k=heap[k].c<heap[right].c?k:right;
    if(k!=t){
        b=heap[k],heap[k]=heap[t],heap[t]=b;
        adjust(k);
    }
}
void pop(){
    heap[1]=heap[s];
    s--;
    adjust(1);//翻看了以前堆的写法
}
struct node2 top(){
    return heap[1];
}
int empty(){
    return !s;
}
void dijkstra(){
    int i,b,u,v;//b边
    struct node2 a;
    memset(vis,0,sizeof(vis));
    for(i=0;i<n;i++)
        d[i]=INF;
    d[0]=0;
    a.c=0,a.v=0;
    push(a);
    while(!empty()){//1此处写成 while(empty())
        a=top();
        pop();
        u=a.v;
        if(vis[u]==1)continue;//已经访问过
        vis[u]=1;
        for(b=head[u];b;b=e[b].next){
            v=e[b].to;
            if(vis[v]==0&&d[v]>d[u]+e[b].c){
                d[v]=d[u]+e[b].c;
                a.v=v,a.c=d[v];
                push(a);
            }
        }
    }
    for(i=0;i<n;i++)
        printf("%d %d\n",i,d[i]);
}
int main(){
    int i,j,u,k,v,c;
    memset(head,0,sizeof(head));
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d%d",&u,&k);
        for(j=1;j<=k;j++){
            scanf("%d%d",&v,&c);
            addedge(u,v,c);
        }
    }
    dijkstra();
    return 0;
}

2017-10-4 17:06 AC该章节内容


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值