从最简单的dijkstra
从这里先读的
题目 HDU 2544
自己照着自己关于dijkstra的理解写的代码T了。1
bool allvis() {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += vis[i];
}
if (sum == n) {
return true;
} else {
return false;
}
}
void dijkstra(int start) {
memset(vis, 0, sizeof(vis));
vis[start] = 1;
while (!allvis()) {
int mincost = MAXNUM;
int nextpos = 0;
for (int i = 0; i < n; i++) {
if (cost[start][i] < mincost && vis[i] == 0) {
mincost = cost[start][i];
nextpos = i;
vis[i] = 1;
}
}
for (int i = 0; i < n; i++) {
if (vis[i] == 0) {
if (cost[nextpos][i] + cost[start][nextpos] < cost[start][i]) {
cost[start][i] = cost[nextpos][i] + cost[start][nextpos];
}
}
}
}
}
判断条件我选择了是所有的点都被遍历一遍,(脑残)。
由于每次 vis[] 中必定会多出一个点,所以只需要遍历 n 次。
别人的代码
bool vis[102];//判断顶点是否被访问过,需要初始化
int d[102];//保存从起点到编号为i的顶点的最短距离d[i]
int w[102][102];//边的价值,w[from][to]
int n,m;//n为顶点数,m为边数
void dijkstra(int start)//最短路dijkstra算法
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
d[i]=(i==start?0:inf);//初始化,起点d[start]=0, 其它均为最大值,inf
for(int i=1;i<=n;i++)
{
int x,mini=inf;//x为未访问过的d[i]存在最小值的那个顶点编号,每次都需要找这个顶点,找n次
for(int y=1;y<=n;y++)
if(!vis[y]&&d[y]<=mini)
{
mini=d[y];
x=y;//两句可以合写为mini=d[x=y];
}
vis[x]=1;//找到的顶点被访问过
for(int y=1;y<=n;y++)
d[y]=min(d[y],d[x]+w[x][y]);
}
}
然后分析别人代码的时候,明白了上午熊猫讲的优化问题,因为每次都要从 cost[] 中找出最小的且未被标记的点。
自己写的代码,刚好最近健行男神讲了优先队列。看着kuangbin的代码自己理解了之后写的。
WA了一发,错在了
if (cost[temp.v][i] + pos[temp.v]< pos[i]) {
pos[i] = cost[temp.v][i] + pos[temp.v];
que.push(qnode(i, pos[i]));
}
还是不是自己完全理解的东西是不自己的。 pos[temp.v] 用的是 cost[start][temp.v] ,这个代码的更新的是 pos[] 。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int inf = 1 << 30;
bool vis[102];
int pos[102];
int cost[102][102];
struct qnode {
int v;
int c;
qnode(int _v = 0, int _c = 0) :
v(_v), c(_c) {
}
bool operator<(const qnode &r) const {
return c > r.c;
}
};
int n, m;
priority_queue<qnode> que;
void dijkstra(int start) {
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++)
pos[i] = (i == start ? 0 : inf);
while (!que.empty()) {
que.pop();
}
que.push(qnode(start, 0));
qnode temp;
while (!que.empty()) {
temp = que.top();
que.pop();
if (vis[temp.v])
continue;
vis[temp.v] = 1;
for (int i = 1; i <= n; i++) {
if (vis[i] == 0) {
if (cost[temp.v][i] + pos[temp.v]< pos[i]) {
pos[i] = cost[temp.v][i] + pos[temp.v];
que.push(qnode(i, pos[i]));
}
}
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
while (cin >> n >> m && n && m) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cost[i][j] = inf;
}
}
for (int i = 1; i <= m; i++) {
int from, to, co;
cin >> from >> to >> co;
if (cost[from][to] > co) {
cost[from][to] = co;
cost[to][from] = co;
}
}
dijkstra(1);
cout << pos[n] << endl;
}
return 0;
}
kuangbin 的模板:
/*
使用优先队列优化Dijkstra算法
复杂度O(ElogE)
注意对vector<Edge>E[MAXN]进行初始化后加边
*/
const int INF=0x3f3f3f3f;
const int MAXN=1000010;
struct qnode
{
int v;
int c;
qnode(int _v=0,int _c=0):v(_v),c(_c){}
bool operator <(const qnode &r)const
{
return c>r.c;
}
};
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
bool vis[MAXN];
int dist[MAXN];
void Dijkstra(int n,int start)//点的编号从1开始
{
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++)
dist[i]=INF;
priority_queue<qnode>que;
while(!que.empty())
que.pop();
dist[start]=0;
que.push(qnode(start,0));
qnode tmp;
while(!que.empty())
{
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])
continue;
vis[u]=true;
for(int i=0;i<E[u].size();i++)
{
int v=E[tmp.v][i].v;
int cost=E[u][i].cost;
if(!vis[v]&&dist[v]>dist[u]+cost)
{
dist[v]=dist[u]+cost;
que.push(qnode(v,dist[v]));
}
}
}
}
按照这种思路又改了一遍,因为考虑了一下,关于找邻接点的时候全部遍历效率还是 n 2 的效率。在构造图的时候以点的邻接点构造,WA了一发,E[MAXN]进行初始化后加边。