挑战程序设计竞赛 算法和数据结构 第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;
}
//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;
}
//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该章节内容