Til the Cows Come Home 最短路Dijkstra+bellman(普通+优化)

贝西在田里,想在农夫约翰叫醒她早上挤奶之前回到谷仓尽可能多地睡一觉。贝西需要她的美梦,所以她想尽快回来。

农场主约翰的田里有n(2<=n<=1000)个地标,唯一编号为1..n。地标1是谷仓;贝西整天站在其中的苹果树林是地标n。奶牛在田里行走时使用地标间不同长度的T(1<=t<=2000)双向牛道。贝西对自己的导航能力没有信心,所以一旦开始,她总是沿着一条从开始到结束的路线行进。

根据地标之间的轨迹,确定贝西返回谷仓必须走的最小距离。这样的路线一定存在。

解题思路

这个题是很典型的最短路问题,并且给了起点和终点,所以使用Dijkstra算法来解决单源最短路问题。

Dijkstra算法我这有两种形式,一种是普通的邻接矩阵法,复杂度是\(O(n^2)\),n是顶点的个数

然而使用邻接表和优先队列的形式,可以将复杂度优化到\(O(m*logn)\),m是边的个数,但是这种一般适用于稀疏图,对于稠密图,这种优化算法可能比原来没有优化的复杂度还要高。参考《算法竞赛入门经典(第二版)》360页

这个题也可以用Bellman算法来进行实现。

代码实现

//普通的临界矩阵算法 dijkstra算法
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int inf=0x3f3f3f3f;
const int maxn=1e3+7;
int mp[maxn][maxn];
int dis[maxn];
int vis[maxn];
int t, n; void dij()
{
for(int i=1; i<=n; i++)
{
dis[i]=mp[1][i];
}
vis[1]=1;
for(int i=1; i<n; i++)
{
int tmp=inf, k;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j]<tmp)
{
tmp=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j] > dis[k]+mp[k][j])
dis[j]=dis[k] + mp[k][j];
}
}
} void init()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i!=j) mp[i][j]=inf;
else mp[i][j]=0;
}
}
fill(vis+1, vis+n+1, 0);
fill(dis+1, dis+n+1, inf);
}
int main()
{
while(scanf("%d%d", &t, &n)!=EOF)
{
int a, b, c;
init();
for(int i=1; i<=t; i++)
{
scanf("%d%d%d", &a, &b, &c);
if(c < mp[a][b])
{
mp[a][b]=c;
mp[b][a]=c;
}
}
dij();
printf("%d\n", dis[n]);
}
return 0;
}

优化的Dijkstra算法

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=1e3+7;
const int maxe=2e3+7;
const int inf=0x3f3f3f3f;
struct edge{
int to, cost;
};
struct headnode{
int d, u;
bool friend operator < (const headnode a, const headnode b)
{
return a.d > b.d; //使用大于号是因为在优先队列中默认是从大到小的,这里需要反过来,从小到大。
}
};
int dis[maxn];
int vis[maxn];
vector<edge> g[maxn];
priority_queue<headnode> que;
int t, n;
void init()
{
for(int i=1; i<=n; i++)
{
g[i].clear();
vis[i]=0;
dis[i]=inf;
}
while(!que.empty()) que.pop();
}
void dij(int s)
{
int u;
edge e;
dis[s]=0;
headnode tmp={0, s};
headnode next;
que.push(tmp);
while(!que.empty())
{
tmp=que.top();
que.pop();
u=tmp.u;
if(vis[u]==1) continue;
vis[u]=1;
for(int i=0; i<g[u].size(); i++)
{
e=g[u][i];
if(dis[e.to] > dis[u]+e.cost)
{
dis[e.to]=dis[u]+e.cost;
next.d=dis[e.to];
next.u=e.to;
que.push(next);
}
}
}
}
int main()
{
while(scanf("%d%d", &t, &n)!=EOF)
{
init();
int a, b, c;
edge e;
for(int i=1; i<=t; i++)
{
scanf("%d%d%d", &a, &b, &c);
e.to=b;
e.cost=c;
g[a].push_back(e);
e.to=a;
e.cost=c;
g[b].push_back(e);
}
dij(1);
printf("%d\n", dis[n]);
}
return 0;
}

Bellman算法

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int maxn=1e3+7;
const int maxe=4e3+7; //这里一定要注意,t是路的条数,但是存图时每条路需要存储两遍。
const int inf=0x3f3f3f3f; struct edge{
int a, b, c;
}e[maxe]; int dis[maxn];
int t, n, cnt; // bool bellman(int s)
{
for(int i=1 ;i<=n; i++)
dis[i]=inf;
dis[s]=0;
bool flag;
int x, y, z;
for(int i=1; i<n; i++)
{
flag=false;
for(int j=1; j<cnt; j++)//cnt-1是边的条数
{
x=e[j].a;
y=e[j].b;
z=e[j].c;
if(dis[y] >= dis[x] + z)
{
dis[y]=dis[x]+z;
flag=true;
}
}
if(!flag)
break;
if(flag && i==n)
return false;
}
return true;
} int main()
{
while(scanf("%d%d", &t, &n)!=EOF)
{
int a, b, c;
cnt=1;
for(int i=1; i<=t; i++)
{
scanf("%d%d%d", &a, &b, &c);
e[cnt].a=a; e[cnt].b=b; e[cnt++].c=c;
e[cnt].a=b; e[cnt].b=a; e[cnt++].c=c;
}
bellman(1);
printf("%d\n", dis[n]);
}
return 0;
}

优化的Bellman算法,也就是鼎鼎大名的SPFA。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1e3+7;
const int inf=0x3f3f3f3f;
struct edge
{
int to, cost;
edge(){}
edge(int a, int b)
{
to=a;
cost=b;
}
};
int dis[maxn];
bool inq[maxn];
int cnt[maxn];
vector<edge> g[maxn];
queue<int>que;
int t, n;
bool spfa(int s)
{
for(int i=1; i<=n; i++)
{
dis[i]=inf;
inq[i]=false;
cnt[maxn]=0;
}
while(!que.empty()) que.pop(); edge e;
dis[s]=0;
inq[s]=true;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
inq[u]=false;
for(int i=0; i<g[u].size() ; i++)
{
e=g[u][i];
if(dis[e.to] > dis[u]+e.cost)
{
dis[e.to] = dis[u]+e.cost;
if(inq[e.to]==false)
{
inq[e.to]=true;
que.push(e.to);
cnt[e.to]++;
if(cnt[e.to]>=n) return false; //这里是记录松弛的次数,如果达到n次说明有负环
}
}
}
}
return true;
}
int main()
{
while(scanf("%d%d", &t, &n)!=EOF)
{
int a, b, c;
for(int i=1; i<=n; i++)
g[i].clear();
for(int i=1; i<=t; i++)
{
scanf("%d%d%d", &a, &b, &c);
g[a].push_back(edge(b, c));
g[b].push_back(edge(a, c));
}
spfa(1);
printf("%d\n", dis[n]);
}
return 0;
}

Til the Cows Come Home 最短路Dijkstra+bellman(普通+优化)的更多相关文章

  1. POJ2387 Til the Cows Come Home (最短路 dijkstra)

    AC代码 POJ2387 Til the Cows Come Home Bessie is out in the field and wants to get back to the barn to ...

  2. 【POJ - 2387】Til the Cows Come Home(最短路径 Dijkstra算法)

    Til the Cows Come Home 大奶牛很热爱加班,他和朋友在凌晨一点吃完海底捞后又一个人回公司加班,为了多加班他希望可以找最短的距离回到公司.深圳市里有N个(2 <= N < ...

  3. Til the Cows Come Home(poj 2387 Dijkstra算法(单源最短路径))

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 32824   Accepted: 11098 Description Bes ...

  4. POJ 2387 Til the Cows Come Home(模板——Dijkstra算法)

    题目连接: http://poj.org/problem?id=2387 Description Bessie is out in the field and wants to get back to ...

  5. Til the Cows Come Home(最短路模板题)

    Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Description Bessie is ...

  6. POJ-2387 Til the Cows Come Home ( 最短路 )

    题目链接: http://poj.org/problem?id=2387 Description Bessie is out in the field and wants to get back to ...

  7. POJ 2387 Til the Cows Come Home --最短路模板题

    Dijkstra模板题,也可以用Floyd算法. 关于Dijkstra算法有两种写法,只有一点细节不同,思想是一样的. 写法1: #include <iostream> #include ...

  8. POJ 2387 Til the Cows Come Home(最短路模板)

    题目链接:http://poj.org/problem?id=2387 题意:有n个城市点,m条边,求n到1的最短路径.n<=1000; m<=2000 就是一个标准的最短路模板. #in ...

  9. POJ 3268 Silver Cow Party 最短路—dijkstra算法的优化。

    POJ 3268 Silver Cow Party Description One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbe ...

随机推荐

  1. (转)Spring实例化

    标签:SpringContextUtil,getBean 手动获取Bean 方法一  不用配置xml,直接java代码实现 /** * 工厂模式选择Bean类 */ public class MyBe ...

  2. hdu 1051 wooden sticks (贪心+巧妙转化)

    #include <iostream>#include<stdio.h>#include<cmath>#include<algorithm>using ...

  3. Android_(控件)动态添加或删除Spinner下拉菜单

    使用ArrayList动态数组的依赖性实现动态增减Spinner下拉菜单选项功能. 设置一个EditText输入框,当用户输入了文字并单击[添加]按钮的同时,就会将输入的值添加Spinner至下拉菜单 ...

  4. 数据预测算法-ARIMA预测

    简介 ARIMA: AutoRegressive Integrated Moving Average ARIMA是两个算法的结合:AR和MA.其公式如下: 是白噪声,均值为0, C是常数. ARIMA ...

  5. 暂时跳过的Leetcode题目

    963 最小面积矩形 II 有数学几何的味道,感觉这不是笔试面试的重点. 932 漂亮数组 构造题

  6. Adding property to a json object in C#

    Adding property to a json object in C#   you can do it with a dynamic object dynamic obj = JsonConve ...

  7. 系统句柄报too many files open

    对于一般的应用来说(象Apache.系统进程)1024完全足够使用.但是如何象java等单进程处理大量请求的应用来说就有点捉襟见肘了.如果单个进程打开的文件句柄数量超过了系统定义的值,就会提到“too ...

  8. 字符 kotlin(3)

    字符 用 Char 类型表示.它们不能直接当作数字) { // 错误:类型不兼容 // …… }} 字符字面值用单引号括起来: '1' . 特殊字符可以用反斜杠转义. 支持这几个转义序列: \t . ...

  9. php面向对象 2

    继承概念:如果一个类有子类,那么该子类会继承父类的一切东西(私有成员访问不到)在定义子类的时候需要加一个关键字:extends特点:单继承,一个类只能有一个父类如果父类中有构造函数,子类在实例化的时候 ...

  10. XPath2Doc,一个半自动采集网页生成Word Docx文件的工具,带企查查和天眼查模板

    原始出处:https://www.cnblogs.com/Charltsing/p/XPath2Doc.html 很多人需要从网站采集一些数据填写Word模板,手工操作费时费力还容易出错,所以我给朋友 ...