一些路径问题


 
 
  
  
最短路径算法有三种,Floyd,dijkstra,Bellman_Ford.其中,Floyd适合用于计算每两点间的路径,dijkstra适合稀疏图,bellman则适合稠密图中的已知起点终点,计算最短路径的问题.时间复杂度,floyd算法为n立方,dijk为n平方,bellman为n平方,其中n是点数.dijk可用堆维护,时间复杂度可减至nlogn,而bellman可用队列维护,此方法于1994年被国人提出,命名比较土鳖叫SPFA(shortest path faster algorithm.).至于如何计算,有了名字,搜一下就ok.
需要出具体路径的广搜题
描述
定义一个二维数组: 
int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
输出
左上角到右下角的最短路径,格式如样例所示。
样例输入
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

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

int maze[7][7], pre[30], vis[30];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

bool isLeagal ( int r, int c )
{
	if ( r < 0 || c < 0 || r > 4 || c > 4 )
		return false;
	if ( maze[r][c] == 1 )
		return false;
	return true;
}

void print ( int des )
{
	if ( pre[des] != -1 )
		print ( pre[des] );
	cout << '(' << des / 5 << ", " << des % 5 << ')' << endl; 
}

void bfs ()
{
	queue<int> que;
	memset(vis,0,sizeof(vis));

	pre[0] = -1;
	vis[0] = true;
	que.push ( 0 );

	int now, next;
	int r, c, tr, tc;

	while ( ! que.empty () )
	{
		now = que.front();
		que.pop();
		r = now / 5;
		c = now % 5;

		for ( int i = 0; i < 4; i++ )
		{
			tr = r + dir[i][0];
			tc = c + dir[i][1];
			next = tr * 5 + tc;
			if ( isLeagal ( tr, tc ) && !vis[next] )
			{
				pre[next] = now;
				if ( next == 24 ) return;
				vis[next] = true;
				que.push(next);
			}
		}
	}
}			

int main()
{
	for ( int i = 0; i < 5; i++ )
		for ( int j = 0; j < 5; j++ )
			cin >> maze[i][j];
	bfs();
	print(24);
	return 0;
}不需要路径但是要判断连通度,考虑并查集方法,题在下面,通过结构体道路数组建图
#include <bits/stdc++.h>
#include <vector>
using namespace std;
int visit[510];
int f[510];
struct road
{
    int x,y;
};
struct road p[5100];
int find1(int x)
{
    if(f[x]!=x)
    {
        f[x]=find1(f[x]);
        return f[x];
    }
    else return x;

}
void merg(int x,int y)
{
    int t1=find1(x);
    int t2=find1(y);
    if(t1!=t2)
    {
        f[t2]=t1;
    }
    return ;
}
int main()
{
    int n,m,i,j,x,y,t,c,count1,count2,r;
    scanf("%d %d",&n,&m);
    memset(visit,0,sizeof(visit));
    for(i=0;i<n;i++)
    {
        f[i]=i;
    }
    for(i=0;i<m;i++)
    {
     scanf("%d %d",&p[i].x,&p[i].y);
     merg(p[i].x,p[i].y);
    }
    count1=0;
    for(i=0;i<n;i++)
    {
     if(f[i]==i){
        count1++;
    }
    }
    scanf("%d",&t);
    for(r=0;r<t;i++)
    {
        for(i=0;i<n;i++)
    {
        f[i]=i;
    }
     scanf("%d",&c);
     visit[c]=1;
     for(j=0;j<m;j++)
     {
       if(visit[p[j].x]||visit[p[j].y])
       {
           continue;
       }
       else{
        merg(p[j].x,p[j].y);
       }
     }
     count2=0;
     for(i=0;i<n;i++)
     {
         if(f[i]==i)
         {
             count2++;
         }
     }
    if(count1==count2||count1+1==count2)
{
        printf("City %d is lost.\n",c);

}
   else
   {
    printf("Red Alert: City %d is lost!\n",c);
    }
    count1=count2;
    }
    int f=0;
    for(i=0;i<n;i++)
    {
        if(visit[i]==1)
        {
            f++;
        }
    }
    if(f==n)
    {
        printf("Game Over.\n");
    }
    return 0;
}



战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。
输入格式:
输入在第一行给出两个整数N(0 <<<N ≤\le≤ 500)和M(≤\le≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。
注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。
输出格式:
对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.。
多条件约束问题-迪克斯特拉

本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。
输入格式:
输入第一行给出2个正整数N(2 ≤\le≤N ≤\le≤ 200,城镇总数)和K(城镇间道路条数),以及己方大本营和敌方大本营的代号。随后N-1行,每行给出除了己方大本营外的一个城镇的代号和驻守的敌军数量,其间以空格分隔。再后面有K行,每行按格式城镇1 城镇2 距离给出两个城镇之间道路的长度。这里设每个城镇(包括双方大本营)的代号是由3个大写英文字母组成的字符串。
输出格式:
按照题目要求找到最合适的进攻路径(题目保证速度最快、解放最多、杀伤最强的路径是唯一的),并在第一行按照格式己方大本营->城镇1->...->敌方大本营输出。第二行顺序输出最快进攻路径的条数、最短进攻距离、歼敌总数,其间以1个空格分隔,行首尾不得有多余空格。

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

char name[233][10];
int dis[3][233];
int pre[233];
int cnt[233];
bool vis[233];
int mp[233][233];
int val[233];
map <string,int> Mp;
const int s = 0,d = 1;
int n,tp;

void Dijkstra()
{
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	memset(pre,-1,sizeof(pre));
	memset(dis[0],INF,sizeof(dis[0]));
	memset(dis[1],0,sizeof(dis[1]));
	memset(dis[2],0,sizeof(dis[2]));
	dis[0][0] = 0;
	dis[1][0] = 1;
	cnt[0] = 1;

	int u;
	while(1)
	{
		u = -1;
		for(int v = 0; v < n; ++v)
		{
			if((!vis[v]) && (u == -1 || dis[0][v] < dis[0][u] || (dis[0][v] == dis[0][u] && dis[1][v] > dis[1][u]) || (dis[0][v] == dis[0][u]
								&& dis[1][v] == dis[1][u] && dis[2][v] > dis[2][u]))) u = v;
		}
        if(u == d) return;
		vis[u] = 1;
      for(int v = 0; v < n; ++v)
		{
			if(vis[v]) continue;
			if(dis[0][v] > dis[0][u]+mp[u][v])
			{
				dis[0][v] = dis[0][u] + mp[u][v];
				dis[1][v] = dis[1][u] + 1;
				dis[2][v] = dis[2][u] + val[v];
				pre[v] = u;
				cnt[v] = cnt[u];
			}
			else if(dis[0][v] == dis[0][u]+mp[u][v] && dis[1][v] < dis[1][u]+1)
			{
				dis[0][v] = dis[0][u] + mp[u][v];
				dis[1][v] = dis[1][u] + 1;
				dis[2][v] = dis[2][u] + val[v];
				pre[v] = u;
				cnt[v] += cnt[u];
			}
			else if(dis[0][v] == dis[0][u]+mp[u][v] && dis[1][v] == dis[1][u]+1 && dis[2][v] < dis[2][u]+val[v])
			{
				dis[0][v] = dis[0][u] + mp[u][v];
				dis[1][v] = dis[1][u] + 1;
				dis[2][v] = dis[2][u] + val[v];
				pre[v] = u;
				cnt[v] += cnt[u];
			}
			else if(dis[0][v] == dis[0][u]+mp[u][v]) cnt[v] += cnt[u];
		}
	}

}

void prt(int u)
{
	if(pre[u] == -1) printf("%s",name[u]);
	else
	{
		prt(pre[u]);
		printf("->%s",name[u]);
	}
}

int main()
{
	//fread("");
	//fwrite("");

	int m;
	char u[10];
	char v[10];

	scanf("%d%d%s%s",&n,&m,name[0],name[1]);

	Mp[name[0]] = 0;
	Mp[name[1]] = 1;
	tp = 2;

	val[0] = 0;
	for(int i = 1; i < n; ++i)
	{
		scanf("%s",u);
		if(Mp.count(u)) scanf("%d",&val[Mp[u]]);
		else
		{
			Mp[u] = tp;
			strcpy(name[tp],u);
			scanf("%d",&val[tp++]);
		}
	}

	int w,uu,vv;
	memset(mp,INF,sizeof(mp));
	while(m--)
	{
		scanf("%s%s%d",u,v,&w);
		uu = Mp[u];
		vv = Mp[v];
		if(w < mp[uu][vv]) mp[uu][vv] = mp[vv][uu] = w;
	}

	Dijkstra();
	prt(1);
	puts("");
	printf("%d %d %d\n",cnt[1],dis[0][1],dis[2][1]);

	return 0;
}


L2-001. 紧急救援

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2<=N<=500)是城市的个数,顺便假设城市的编号为0~(N-1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出不同的最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出首尾不能有多余空格

/*
    dijkstra模板,可以计算最短路的长度,结果保存在dis[]中;
	如果有多条最短路,可以计算最短的条数,结果保存在num[]中;
	同时利用前缀数组记录最短路的路径,输出利用栈(stack);
	a[]数组表示每个点的权值,要求最后最短路的权值最大,结果保存在maxx[]中。
	
	
	patL2-1. 紧急救援。很不错大家可以理解试一试,最重要的是理解。
*/

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int N = 505;
int n,m,s,e;
int map[N][N];   //利用邻接矩阵保存图
int dis[N];      //最短路值
int vis[N];      //标记数组
int num[N];     //路径个数
int maxx[N];    //最短路径最大的权值和
int a[N];       //每个点的权值
int pre[N];     //保存路径,记录前驱
void dij(int start){
	int i;
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;i++){
		if(i==start) {
			dis[i]=0;
			maxx[i]=a[i];
		}
		else {
			dis[i]=map[start][i];
			maxx[i]=a[start]+a[i];   //重要  maxx初始化
		}
		
		if(i!=start&&map[start][i]!=inf)
			pre[i]=start;
		else
			pre[i]=-1;
	}
	vis[start]=1;
	for(i=0;i<n;i++){
		int t=inf,j,k;
		for(j=0;j<n;j++){
			if(!vis[j]&&t>dis[j]){
				t=dis[j];
				k=j;
			}
		}
		if(t==inf){
			break;    //不连通
		}
		vis[k]=1;
		for(j=0;j<n;j++){
			if(!vis[j]){
				if(dis[j]>dis[k]+map[k][j]){
					dis[j]=dis[k]+map[k][j];
					maxx[j]=maxx[k]+a[j];
					num[j]=num[k];
					pre[j]=k;
				}
				else if(dis[j]==dis[k]+map[k][j]){
					num[j]=num[j]+num[k];
					if(maxx[j]<maxx[k]+a[j]){
						maxx[j]=maxx[k]+a[j];
						pre[j]=k;
					}
					//maxx[j]=max(maxx[j],maxx[k]+a[j]);
				}
			}
		}
	}
}
//输出路径   结尾换行,中间用空格隔开,且最后一个数后没有空格
void print_path(){
 	stack<int> S;
	for(int i=e;i!=-1;i=pre[i])
		S.push(i);
	int flag=0;
	while(!S.empty()){
		if(flag)
			printf(" ");
		else
			flag=1;
		printf("%d",S.top());
		S.pop();
	}
	printf("\n");
}
int main(){
	while(~scanf("%d %d %d %d",&n,&m,&s,&e)){
		int i,j;
		for(i=0;i<n;i++){
			scanf("%d",&a[i]);
			num[i]=1;
		}
		memset(map,inf,sizeof(map));
		for(i=0;i<m;i++){
			int ss,ee,ww;
			scanf("%d %d %d",&ss,&ee,&ww);
			map[ss][ee]=min(map[ss][ee],ww);   //避免存在重复的路径
			map[ee][ss]=min(map[ee][ss],ww);
		}
		dij(s);
		printf("%d %d\n",num[e],maxx[e]);
		//输出路径
		print_path();
	}
	return 0;
}




  
  


  
  


 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值