1003 Emergency(迪杰斯特拉)

1003 Emergency

//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;  //最大顶点数
const int INF = 1000000;
int n, m, st, ed, weight[maxn], G[maxn][maxn];     //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], w[maxn], num[maxn];        //起点到各个顶点的最短路径长度
//int pre[maxn];      //结点的前驱
bool vis[maxn] = {false};       //标记是否访问

void Dijkstra(int s)
{
    fill(d, d + maxn, INF);
    memset(w, 0, sizeof(w));
    memset(num, 0, sizeof(num));
    d[s] = 0;
    w[s] = weight[s];
    num[s] = 1;
    //n次循环
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = INF;        	//使d[u]最小的还未被访问过的顶点的标号     MIN存放最小的d[u]
        for(int j = 0; j < n; j++)          //找到未访问顶点中d[]最小的
        {
            if(vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;     //找不到小于INF的d[u],说明剩下的顶点和s不连通
        vis[u] = true;          //标记u已经被访问
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && G[u][v] != INF)
            {
                if(G[u][v] + d[u] < d[v])	//以u为中介点可以使d[v]更优
                {
                    d[v] = G[u][v] + d[u];
                    w[v] = w[u] + weight[v];
                    num[v] = num[u];
                }
//                else if(G[u][v] + d[u] == d[v] && w[u] + weight[v] > w[v])
                else if(G[u][v] + d[u] == d[v])
                {
                    if(w[u] + weight[v] > w[v])
                    {
                        w[v] = w[u] + weight[v];
                    }
                    num[v] += num[u];	//最短路径与点权无关,必须写在外面
                }
                
            }
        }


    }
}

//void DFS(int s,int v)   //输出最短路径
//{
//    if(v == s)
//    {
//        printf("%d ", s);
//        return;
//    }
//    DFS(s, pre[v]);
//    printf("%d ", v);
//}

int main()
{

    scanf("%d%d%d%d", &n, &m, &st, &ed);
//    scanf("%d%d%d", &n, &m, &s);    //n为顶点数,m为边数,s为起点
    for(int i = 0; i < n; i++)
        scanf("%d", &weight[i]);
    int u, v;
    fill(G[0], G[0] + maxn * maxn, INF);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);    //有向边
        scanf("%d", &G[u][v]);
        G[v][u] = G[u][v];
//        G[u][v] = w;
        //如果是无向边,只需要把无向边堪称两条相反的有向边即可
        //对于邻接矩阵,G[u][v]和G[v][u]赋相同的权值即可
        //对于邻接表,Adj[v]加上u,Adj[u]加上v即可
    }
    Dijkstra(st);
    printf("%d %d", num[ed], w[ed]);
//    DFS(0, 2);
	return 0;
}




这样也可以,区别主要在于那个for循环条件的个数。

//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;  //最大顶点数
const int INF = 1000000;
int n, m, st, ed, weight[maxn], G[maxn][maxn];     //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], w[maxn], num[maxn];        //起点到各个顶点的最短路径长度
//int pre[maxn];      //结点的前驱
bool vis[maxn] = {false};       //标记是否访问

void Dijkstra(int s)
{
    fill(d, d + maxn, INF);
    memset(w, 0, sizeof(w));
    memset(num, 0, sizeof(num));
    d[s] = 0;
    w[s] = weight[s];
    num[s] = 1;
    //n次循环
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = INF;        	//使d[u]最小的还未被访问过的顶点的标号     MIN存放最小的d[u]
        for(int j = 0; j < n; j++)          //找到未访问顶点中d[]最小的
        {
            if(vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;     //找不到小于INF的d[u],说明剩下的顶点和s不连通
        vis[u] = true;          //标记u已经被访问
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] < d[v])
            {
                	//以u为中介点可以使d[v]更优

                    d[v] = G[u][v] + d[u];
                    w[v] = w[u] + weight[v];
                    num[v] = num[u];
            }
//                else if(G[u][v] + d[u] == d[v] && w[u] + weight[v] > w[v])
            else if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] == d[v])
            {
                if(w[u] + weight[v] > w[v])
                {
                    w[v] = w[u] + weight[v];
                }
                num[v] += num[u];
            }
        }
    }
}


//void DFS(int s,int v)   //输出最短路径
//{
//    if(v == s)
//    {
//        printf("%d ", s);
//        return;
//    }
//    DFS(s, pre[v]);
//    printf("%d ", v);
//}

int main()
{

    scanf("%d%d%d%d", &n, &m, &st, &ed);
//    scanf("%d%d%d", &n, &m, &s);    //n为顶点数,m为边数,s为起点
    for(int i = 0; i < n; i++)
        scanf("%d", &weight[i]);
    int u, v;
    fill(G[0], G[0] + maxn * maxn, INF);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);    //有向边
        scanf("%d", &G[u][v]);
        G[v][u] = G[u][v];
//        G[u][v] = w;
        //如果是无向边,只需要把无向边堪称两条相反的有向边即可
        //对于邻接矩阵,G[u][v]和G[v][u]赋相同的权值即可
        //对于邻接表,Adj[v]加上u,Adj[u]加上v即可
    }
    Dijkstra(st);
    printf("%d %d", num[ed], w[ed]);
//    DFS(0, 2);
	return 0;
}




最短路径

//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;  //最大顶点数
const int INF = 1000000;
int n, m, s;     //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], G[maxn][maxn];        //起点到各个顶点的最短路径长度
int pre[maxn];      //结点的前驱
bool vis[maxn] = {false};       //标记是否访问

void Dijkstra(int s)
{
    fill(d, d + maxn, INF);
    for(int i = 0; i < n; i++)
        pre[i] = i; //初始状态每个节点的前驱为自身(新增)
    d[s] = 0;
    //n次循环
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = INF;        	//使d[u]最小的还未被访问过的顶点的标号     MIN存放最小的d[u]
        for(int j = 0; j < n; j++)          //找到未访问顶点中d[]最小的
        {
            if(vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;     //找不到小于INF的d[u],说明剩下的顶点和s不连通
        vis[u] = true;          //标记u已经被访问
        for(int v = 0; v < n; v++)
        {   //以u为中介点可以使d[v]更优
            if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] < d[v])
            {
                    d[v] = G[u][v] + d[u];
                    pre[v] = u;     //记录v的前驱顶点是u(新增)
            }
        }
    }
}


void DFS(int s,int v)   //输出最短路径
{
    if(v == s)
    {
        printf("%d ", s);
        return;
    }
    DFS(s, pre[v]);
    printf("%d ", v);
}

int main()
{
    int u, v, w;
    scanf("%d%d%d", &n, &m, &s);    //n为顶点数,m为边数,s为起点
    fill(G[0], G[0] + maxn * maxn, INF);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &u, &v, &w);
        G[u][v] = w;
    }
    Dijkstra(s);
    for(int i = 0; i < n; i++)
        printf("%d ", d[i]);
    printf("\n到各个点的距离为:\n");
    for(int i = 0; i < n; i++)
    {
        printf("\n");
        DFS(0, i);
    }
	return 0;
}




输入:

6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3

输出

0 1 5 3 4 6
到各个点的距离为:

0
0 1
0 1 3 2
0 1 3
0 4
0 1 3 2 5

之前的写法中,pre[i]初始化为i,这种写法pre[v]并不需要初始化。
如果G[u][v] + d[u] < d[v],说明以u为中介可以使d[v]更优,此时pre[v]要先清空,然后再添加u。

if(G[u][v] + d[u] < d[v])
{
	d[v] = G[u][v] + d[u]
	pre[v].clear();
	pre[v].push_back(u);
}

如果G[u][v] + d[u] = d[v],此时只需要再原来的基础上添加u

if(G[u][v] + d[u] == d[v])
	pre[v].push_back(u);
vector<int> pre[maxn];
void Dijkstra_1(int s)
{
    fill(d, d + maxn, INF);
    d[s] = 0;
    for(int i = 0; i < n; i++)
    {
        int u = - 1, MIN = INF;
        for(int j = 0; j < n; j++)
        {
            if(vis[j] == false && d[j] < INF)
            {
                u = j;
                MIN = d[j];
            }
        }
        if(u == -1) return;
        vis[u] == true;
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && &&G[u][v] != INF)
            {
                if(G[u][v] + d[u] < d[v])
                {
                    d[v] = G[u][v] + d[u]
                    pre[v].clear();
                    pre[v].push_back(u);	//令v的前驱为u
                }
                else if(G[u][v] + d[u] == d[v])
                {
                    pre[v].push_back(u);	//令v的前驱为u
                }
            }
        }
    }
}

SPFA做法:

#include<bits/stdc++.h>
using namespace std;

const int MAXN=501;
const int INF=1000000;
int n, m, st, ed, weight[MAXN];
int d[MAXN], w[MAXN], num[MAXN], cnt[MAXN]; //num路径条数, cnt入队次数
bool inq[MAXN] = {false};
set<int> pre[MAXN];
struct Node{
	int v,dis;
	Node(int _v,int _dis):v(_v),dis(_dis){
	};//构造函数 
};
vector<Node> Adj[MAXN];
bool SPFA(int s){
	fill(d,d+MAXN,INF);
	memset(w,0,sizeof(w));
	memset(num,0,sizeof(num));
	queue<int> Q;
	Q.push(s);
	//s在队列里
	inq[s]=true;
	d[s]=0;
	w[s]=weight[s];
	num[s]=1;
	cnt[s]=1;//源点入队次数+1 
	while(!Q.empty()){
		int u=Q.front();
		Q.pop();
		inq[u]=false;
		for(int j=0;j<Adj[u].size();j++){
			int v=Adj[u][j].v;
			int dis=Adj[u][j].dis;
			if(d[u]+dis<d[v]){
				d[v]=d[u]+dis;
				w[v]=w[u]+weight[v];
				pre[v].clear();
				pre[v].insert(u);
				num[v]=num[u];
				if(!inq[v]){
				Q.push(v);
				//v的入队次数+1 
				cnt[v]++;
				inq[v]=true;
				}
			}else if(d[u]+dis==d[v]){
				if(w[u]+weight[v]>w[v]){
					w[v]=w[u]+weight[v];
				}
				pre[v].insert(u);
				num[v]=0;       //重新统计num[v]
				set<int>::iterator it;
				for(it=pre[v].begin();it!=pre[v].end();it++){
					num[v]+=num[*it];
				}
				//无论w[v]是否改变,num[v]都有可能改变,所以入队 
				if(!inq[v]){
				Q.push(v);
				cnt[v]++;
				inq[v]=true;
				}
			}
			//只要某一点入队次数>=n
			//则原图中有负环,则不可得到结果
			if(cnt[v]>=n) return false;
		}
	}
	return true;
}


int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d%d%d%d",&n,&m,&st,&ed);
	for(int i=0;i<n;i++){
		scanf("%d",&weight[i]);
	}
	int u,v,wt;
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&u,&v,&wt);
		Adj[u].push_back(Node(v,wt));
		Adj[v].push_back(Node(u,wt));
	}
	bool ok=SPFA(st);
	if(ok) printf("%d %d",num[ed],w[ed]);
	else printf("有负环!"); 
	return 0;
}
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值