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. json的值键对,对象,数组,逻辑值

    详细说一下有关json的相关知识: ㈠json与xml的异同 ★与 XML 相同之处 ⑴JSON 是纯文本 ⑵JSON 具有"自我描述性"(人类可读) ⑶JSON 具有层级结构(值 ...

  2. no matches for kind "ReplicaSet" in version "extensions/v1beta1"

    原来的yaml的资源清单为 apiVersion: extensions/v1beta1 kind: ReplicaSet metadata: name: frontend spec: replica ...

  3. K8S容器探针

    容器探针 探针是由 kubelet对容器执行的定期诊断.要执行诊断, kubelet 调用由容器实现的    Handler .有三种类型的处理程序:   ExecAction :在容器内执行指定命令 ...

  4. python中assert的用法

    assert:断言 格式: assert 表达式 [, 参数] 当表达式为真时,程序继续往下执行: 当表达式为假时,抛出AssertionError错误,并将  参数  输出 举例: def foo( ...

  5. postfix -- 发件调试

    按照教程(https://www.cnblogs.com/huandada/p/10554603.html)搭建好postfix之后,由于收件的邮件运营商的限制,部分邮件不能正常发送,需要更多其他配置 ...

  6. [JZOJ5398]:Adore(状压DP+记忆化搜索)

    题目描述 小$w$偶然间见到了一个$DAG$. 这个$DAG$有$m$层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有$k$个节点. 现在小$w$每次可以取反第$i(1<i< ...

  7. Mac开发如何处理键盘事件

    Mac上输入与手机输入的不同是,Mac需要处理更多的键盘交互,因为Mac上的键盘输入会有多种快捷键组合. 代理方法处理 NSTextField #pragma mark - NSTextFieldDe ...

  8. Docker入门-构建第一个Java程序

    定制镜像 准备一个没有第三方依赖的java web项目,可能参考示例maven结构项目: session-web.war 把该war上传到安装有docker软件的服务器上宿主目录下.在同级目录创建Do ...

  9. 使用C#语言,将DataTable 转换成域模型

    DataTable dt = SqlHelper.Query(strQuery); ) * size).Take(pagesize); List<Model> listData = new ...

  10. Oracle Rac 测试

      #还是使用之前的脚步来进行测试 #Author : Kconnie Pong Oracle@PONGDB:~> more load_balance.sh #!/bin/bash ..} do ...