2011年北京大学计算机研究生机试真题(dijkstra+优先队列)

http://ac.jobdu.com/problem.php?pid=1162  I Wanna Go Home

方法一:普通的dijkstra

/*
很明显的最短路,但关键是如何建图。可以看到,一共只有两种走法,一种是从city1出发,一直走属于group1的city直到city2,

或者一直走属于group2的city直到city1。我昨天建了两个图来表示两种情况,分别求最短路,然后取小的,结果越写越乱。今天发现其实一次就

可以,只要在建图的时候,如果两个city属于一个group,就建双向图,否则就建从属于group1的city到属于group2的city的单向图。原因很简单,

因为两种情况都不会出现从2到1的情况。建好图然后就简单了,注意无解的情况。
*/
#include<iostream>
#include<cstdio>
using namespace std;
#include<memory.h>

int map[601][601],x[601];
int dijkstra(int n,int start,int end)   //start是原点,n是图中所有点的个数
{
	int visit[601];    //判断是否已存入该点到visit集合中
	int i,j,k,min,t;
	for (i=1;i<=n;i++)
	{
		x[i]=map[start][i];
		visit[i]=0;   //初始都未用过该点
	}
	x[start]=0;
	visit[start]=1;
	// 依次将未放入visit集合的结点中,取x[]最小值的结点,放入集合visit中
	// 一旦visit包含了所有顶点,x就记录了从源点到所有其他顶点之间的最短路径长度
	// 注意是从第二个节点开始,第一个为源点
	for(i=2;i<=n;i++)
	{
		min = 16843009;
		t=-1;
		// 找出当前未使用的点j的x[j]最小值
		for(j=1; j<=n; ++j)
		{
			if(!visit[j] && x[j]<min)
			{
				t = j;              // t保存当前邻接点中距离最小的点的号码
				min = x[j];
			}
		}
		if(t!=-1)
		{
			visit[t] = 1;    // 将t点存入visit集合中
			// 更新x的值
			for(j=1; j<=n; ++j)
			{
				if (!visit[j] && min+map[t][j]<x[j])
					x[j]=min+map[t][j];
			}
		}
	}
	if(x[end]<16843009)
		return x[end];
	else
		return -1;
}
int main(void)
{
	int i,j,n,m,from,to,cost,group[601];
	while(scanf("%d",&n),n)
	{
		scanf("%d",&m);
		
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(i==j)
					map[i][j]=0;
				else
					map[i][j]=16843009;
			}
		}
		//memset(map,1,sizeof(map));

		for(i=0;i<m;i++)
		{
			scanf("%d %d %d",&from,&to,&cost);
			if(cost<map[from][to])
				map[from][to]=map[to][from]=cost;
		}
		for(i=1;i<=n;i++)
			scanf("%d",&group[i]);
		for(i=1;i<n;i++)
		{
			for(j=i+1;j<=n;j++)
			{
				if(group[i]==group[j])      //如果是一个group,不用管
					continue;
				else if(group[i]==1 && group[j]==2)      //如果一个是1一个是2,则建单向边 
					map[j][i]=16843009;
				else if(group[i]==2 && group[j]==1)      //如果一个是1一个是2,则建单向边 
					map[i][j]=16843009;
			}
		}
		printf("%d\n",dijkstra(n,1,2));
	}
	return 0;
}

 方法二:优先队列+邻接表 来实现dijkstra算法

/*
优先队列+邻接表 来实现dijkstra算法
根据下面的那个模板来修改过来的
*/
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#include<memory.h>

#define INF 16843009
#define MAXN 601  //结点的个数

typedef struct Edge
{
    int adj;
    struct Edge *next;
    int cost;
}Edge,*pEdge;
Edge edge[MAXN];

typedef struct Heap
{
    bool operator <(Heap T)const
    {
        return T.dis<dis;
    }
    int x;
    int dis;
}Heap;

struct Node
{
	int from,to,cost;
}node[10001];

void insert_adjlist(int a,int b, int c)    //创建邻接表
{
    pEdge p,q;
    p=&edge[a];    
    while(p->next!=NULL)
        p=p->next;
    q=new Edge;
    q->adj=b;
    q->next=NULL;
    q->cost=c;
    p->next=q;    
}

int dijkstra(int n,int start,int end)   //start是原点,n是图中所有点的个数
{
	int i,x[MAXN];
	bool visit[MAXN];
	Heap cur,in;
	pEdge p;

	memset(visit,false,sizeof(visit));
	for(i=1;i<=n;i++)
			x[i]=INF;
	priority_queue< Heap >q;  //优先级队列

	cur.x=start;
	cur.dis=0;
	x[start]=0;
	q.push(cur);
	while(!q.empty())
	{
		cur = q.top();
		q.pop();
		if(cur.x == end)    //找到终点
			return cur.dis;
		if(visit[cur.x])   //访问过
			continue;
		visit[cur.x]=true;
		p=edge[cur.x].next;
		while(p!=NULL)
		{
			if(!visit[p->adj])
			{
				in.x=p->adj;
				in.dis=cur.dis+p->cost;
				if(in.dis<x[in.x])
				{
					x[in.x]=in.dis;
					q.push(in);
				}
			}
			p=p->next;
		}
	}
	return -1;
}

int main(void)
{
	int i,j,n,m,from,to,group[601];
	while(scanf("%d",&n),n)
	{
		scanf("%d",&m);
		for(i=1;i<=n;i++)
			edge[i].next=NULL;

		for(i=0;i<m;i++)
		{
			scanf("%d %d %d",&node[i].from,&node[i].to,&node[i].cost);   //暂时保存起来
		}
		for(i=1;i<=n;i++)
			scanf("%d",&group[i]);

		for(i=0;i<m;i++)
		{
			from=node[i].from;
			to=node[i].to;
			if(group[from]==group[to])      //如果是一个group,建立双向边
			{
				insert_adjlist(from,to,node[i].cost);
				insert_adjlist(to,from,node[i].cost); 
			}
			else if(group[from]==1 && group[to]==2)      //如果一个是1一个是2,则建单向边
				insert_adjlist(from,to,node[i].cost);
			else if(group[from]==2 && group[to]==1)      //如果一个是1一个是2,则建单向边
				insert_adjlist(to,from,node[i].cost); 
		}
		printf("%d\n",dijkstra(n,1,2));
	}
	return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=2544 最短路

//优先队列+邻接表 来实现dijkstra算法(模板)
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#include<memory.h>

#define INF 16843009
#define MAXN 601  //结点的个数

typedef struct Edge
{
    int adj;
    struct Edge *next;
    int cost;
}Edge,*pEdge;
Edge edge[MAXN];

typedef struct Heap
{
    bool operator <(Heap T)const
    {
        return T.dis<dis;
    }
    int x;
    int dis;
}Heap;

void insert_adjlist(int a,int b, int c)    //创建邻接表
{
    pEdge p,q;
    p=&edge[a];    
    while(p->next!=NULL)
        p=p->next;
    q=new Edge;
    q->adj=b;
    q->next=NULL;
    q->cost=c;
    p->next=q;    
}

int dijkstra(int n,int start,int end)   //start是原点,n是图中所有点的个数
{
	int i,x[MAXN];
	bool visit[MAXN];
	Heap cur,in;
	pEdge p;

	memset(visit,false,sizeof(visit));
	for(i=1;i<=n;i++)
		x[i]=INF;
	priority_queue< Heap >q;  //优先级队列

	cur.x=start;
	cur.dis=0;
	x[start]=0;
	q.push(cur);
	while(!q.empty())
	{
		cur = q.top();
		q.pop();
		if(cur.x == end)
			return cur.dis;
		if(visit[cur.x])
			continue;
		visit[cur.x]=true;
		p=edge[cur.x].next;
		while(p!=NULL)
		{
			if(!visit[p->adj])
			{
				in.x=p->adj;
				in.dis=cur.dis+p->cost;
				if(in.dis<x[in.x])
				{
					x[in.x]=in.dis;
					q.push(in);
				}
			}
			p=p->next;
		}
	}
	return -1;
}

int main(void)
{
	int i,j,n,m,from,to,cost,group[601];
	while(scanf("%d %d",&n,&m),n+m)
	{
		for(i=1;i<=n;i++)
			edge[i].next=NULL;
		for(i=0;i<m;i++)
		{
			scanf("%d %d %d",&from,&to,&cost);
            insert_adjlist(from,to,cost);
            insert_adjlist(to,from,cost); 
		}
		printf("%d\n",dijkstra(n,1,n));
	}
	return 0;
}

你可能感兴趣的:(c,算法,struct,null,ini,insert)