POJ 3159 candies总结
2012-03-21 20:26
274 查看
此题使用BellmanFord算法效果不佳,POJ提示超时,下面有一个算法使用dijkstra算法速度较快
使用dijkstra算法实现
下面版本是由我写的,没有做任何优化
上面的算法基本上都会出现TLE,使用栈要比队列好,具体为什么可能是测试数据的原因,使用队列的时候要对堆进行push_heap和pop_heap,这儿pop_heap实际上可以省略,那么将意味着效果更好,但是对SPFA优先队列无用,但此方案对Dijkstra有用,而此题目的意思是使用SPFA解决(因为其中有负边),虽然我写的Dijkstra算法也提交成功了,但我认为使用Dijkstra是不对的,使用map对查找最小值有一定的优化,或者我们应该考虑使用斐波那契堆,下面是对Dijkstra算法的一个优化版本
最后不得不提的是scanf的读取问题,scanf读取整数的时候速度会很慢,使用下面实现的读取整数的函数会极大提升程序执行速度
最终得如下程序,经测试,是POJ3159目前发现最快的一个程序47MS
/*------------------------------------------------------------------- * Purpose: * POJ 3159 candies 做了一些优化 * Time: * 2012年3月21日 9:27:16 * Author: * 张彦升 -------------------------------------------------------------------*/ #include <iostream> using namespace std; const int INF = 0x3f3f3f3f; const int V = 30001; const int E = 150001; int pnt[E],cost[E],nxt[E]; int e,head[V]; int dist[V]; bool vis[V]; int relax(int u,int v,int c) { if (dist[v] > dist[u] + c) { dist[v] = dist[u] + c; return 1; } return 0; } void addedge(int u,int v,int c) { pnt[e] = v; cost[e] = c; nxt[e] = head[u]; head[u] = e++; } int SPFA(int src,int n) { int i; for (i = 1;i <= n;i ++) { vis[i] = 0; dist[i] = INF; } dist[src] = 0; int Q[E],top = 1; Q[0] = src; vis[src] = true; while (top) { int u,v; u = Q[--top]; vis[u] = false; for (i = head[u];i != -1;i = nxt[i]) { v = pnt[i]; if (1 == relax(u,v,cost[i]) && !vis[v]) { Q[top++] = v; vis[v] = true; } } } return dist ; } int main() { int n,m; while (scanf("%d%d",&n,&m) != EOF) { int i,a,b,c; e = 0; memset(head,-1,sizeof(head)); for (i = 0;i < m;++i) { cin >> a >> b >> c; addedge(a,b,c); } cout << SPFA(1,n) << endl; } return 0; }
使用dijkstra算法实现
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; //邻接表+优先级队列+dijkstra const int maxn=160000; const int inf=(1<<27); struct edge { int t,w;//s->t=w; int next;//s->的下一个定点 }; int p[maxn];//表头结点 初值-1 edge G[maxn];//邻接表 int l;//邻接表 初值0 int V,E;//点数 边数 //添加边 void addedge(int u,int v,int w) { G[l].t=v; G[l].w=w; G[l].next=p[u]; p[u]=l++; } //计算从s0到其他点的最短距离 struct CNode { int k,w;//s0->k=w; }; bool operator < ( const CNode & d1, const CNode & d2 ) { return d1.w > d2.w; //priority_queue总是将最大的元素出列 } priority_queue<CNode> q; bool vis[maxn]; int dis[maxn];//s0到其他点的最短距离 CNode tmp;//temp void priority_queue_dijkstra(int s0) { memset(vis,0,sizeof(vis)); memset(dis,-1,sizeof(dis)); tmp.k=s0,tmp.w=0; q.push(tmp); while(!q.empty()) { tmp=q.top();q.pop(); if(vis[tmp.k]) continue; vis[tmp.k]=true; dis[tmp.k]=tmp.w; for(int i=p[tmp.k];i!=-1;i=G[i].next) { CNode t; t.k=G[i].t; if(vis[t.k]) continue; t.w=tmp.w+G[i].w; q.push(t); } } } int main() { while(scanf("%d%d",&V,&E)==2) { memset(p,-1,sizeof(p));//important l=0;//important for(int i=0;i<E;i++) { int u,v,w;scanf("%d%d%d",&u,&v,&w);//从1开始 //u->v=w addedge(u,v,w); } priority_queue_dijkstra(1); printf("%d\n",dis[V - 2]); } return 0; }
下面版本是由我写的,没有做任何优化
/*------------------------------------------------------------------- * Purpose: * Candies Bellman Ford * 为了竞赛,必须适应不用类封装而使用全局数据 * Time: * 2012年3月21日 18:46:30 * Author: * 张彦升 -------------------------------------------------------------------*/ #include <iostream> #include <vector> #include <algorithm> #include <fstream> using namespace std; /*我们需要顶点信息和边信息*/ struct Edge { int u; int v; int w; Edge(int t_u,int t_v,int t_w) :u(t_u), v(t_v), w(t_w) { return; } }; typedef vector<Edge> VecEdge; typedef vector<int> VecInt; class Candies { public: /** * **/ Candies(int t_n,int t_m) :n(t_n), m(t_m), dist(n,inf) { dist[0] = 0; return; } /** * **/ ~Candies() { return; } /** * 添加一条新边 */ int addedge(int u,int v,int w) { edge.push_back(Edge(u,v,w)); return 0; } /** * bellman ford algorithm */ int bellman_ford() { /*对于每个节点松弛一次所有边*/ for (int i = 0;i < n;i ++) { relax_edge(); } /*如果一切正常,返回到此点的最短路径*/ if (is_relax_ok() == true) { return 1; } return -1; } /** * 返回路径 */ int get_dis(int pos) { return dist[pos]; } /** * 松弛每条边 */ int relax_edge() { VecEdge::iterator iter = edge.begin(); int ret = 1; for (;iter != edge.end();++iter) { if (0 == relax(*iter)) { ret = 0; } } return ret; } /** * 松弛改变 */ int relax(Edge ed) { int v = ed.v - 1,u = ed.u - 1,w = ed.w; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; return 1; } return 0; } /** * 对负权回路进行检查 */ bool is_relax_ok() { if (relax_edge() == 1) { return false; } return true; } protected: VecEdge edge; /*记录所有的边信息*/ int n,m; /*n is kids number,m is cases number*/ VecInt dist; static const int inf = 0x3f3f3f3f; private: }; /** * 此题中我们不需要保存前点的信息 */ int main() { /*n child and m cases*/ int n,m; //fstream cin("data.txt",ios_base::in); while (cin >> n >> m) { Candies candies(n,m); int u,v,w; /*w = (u,v)*/ for (int i = 0;i < m;i++) { cin >> u >> v >> w; candies.addedge(u,v,w); } /*加入所有边之后开始执行BellmanFord算法*/ /*计算得出结果*/ if (candies.bellman_ford() == -1) { cout << "此图存在错误" << endl; } cout << candies.get_dis(n - 1) << endl; /* for (int i = 0;i < n;i++) { cout << candies.get_dis(i) << endl; } */ } return 0; }
上面的算法基本上都会出现TLE,使用栈要比队列好,具体为什么可能是测试数据的原因,使用队列的时候要对堆进行push_heap和pop_heap,这儿pop_heap实际上可以省略,那么将意味着效果更好,但是对SPFA优先队列无用,但此方案对Dijkstra有用,而此题目的意思是使用SPFA解决(因为其中有负边),虽然我写的Dijkstra算法也提交成功了,但我认为使用Dijkstra是不对的,使用map对查找最小值有一定的优化,或者我们应该考虑使用斐波那契堆,下面是对Dijkstra算法的一个优化版本
/** * v_size表示节点的个数,src表示起始节点 */ int dijkstra(int v_size,int src) { typedef pair<int,int> Node; typedef multimap<int,int,less<int> > DijHeap; DijHeap heap; heap.insert(make_pair(0,src)); dis[src] = 0; register int u,v,w,j; Edge ed; DijHeap::iterator iter,temp; /*循环对没一个顶点访问*/ for (int i = 0; i < v_size;i++) { iter = heap.begin(); j = i; while (j-- > 0) { ++iter; } u = iter->second; if (vis[u] == 1) { continue; } else { vis[u] = 1; } for (j = head[u];j != -1;j = ed.next) { ed = edge[j]; v = ed.v; w = ed.w; if (vis[v] == 0 && dis[v] > dis[u] + w) { dis[v] = dis[u] + w; heap.insert(make_pair(dis[v],v)); } } } return 0; }
最后不得不提的是scanf的读取问题,scanf读取整数的时候速度会很慢,使用下面实现的读取整数的函数会极大提升程序执行速度
/** * 读取一个int */ inline int read_int() { int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; }while(isdigit(tmp=getchar())); return ret; }
最终得如下程序,经测试,是POJ3159目前发现最快的一个程序47MS
/*-------------------------------------------------------------------
* Purpose:
* POJ 3159 candies 做了一些优化
* Time:
* 2012年3月21日 9:27:16
* Author:
* 张彦升
-------------------------------------------------------------------*/
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int V = 30001;
const int E = 150001;
int pnt[E],cost[E],nxt[E];
int e,head[V];
int dist[V];
bool vis[V];
int relax(int u,int v,int c)
{
if (dist[v] > dist[u] + c)
{
dist[v] = dist[u] + c;
return 1;
}
return 0;
}
/** * 读取一个int */ inline int read_int() { int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; }while(isdigit(tmp=getchar())); return ret; }
void addedge(int u,int v,int c)
{
pnt[e] = v;
cost[e] = c;
nxt[e] = head[u];
head[u] = e++;
}
int SPFA(int src,int n)
{
int i;
for (i = 1;i <= n;i ++)
{
vis[i] = 0;
dist[i] = INF;
}
dist[src] = 0;
int Q[E],top = 1;
Q[0] = src;
vis[src] = true;
while (top)
{
int u,v;
u = Q[--top];
vis[u] = false;
for (i = head[u];i != -1;i = nxt[i])
{
v = pnt[i];
if (1 == relax(u,v,cost[i]) && !vis[v])
{
Q[top++] = v;
vis[v] = true;
}
}
}
return dist
;
}
int main()
{
int n,m;
while (scanf("%d%d",&n,&m) != EOF)
{
int i,a,b,c;
e = 0;
memset(head,-1,sizeof(head));
for (i = 0;i < m;++i)
{
//cin >> a >> b >> c;
a = read_int();
b = read_int();
c = read_int();
addedge(a,b,c);
}
cout << SPFA(1,n) << endl;
}
return 0;
}
相关文章推荐
- POJ 3159 Candies
- POJ 3159 Candies (栈优化spfa)
- POJ 3159 Candies (差分约束 Dijkstra+优先队列 SPFA+栈)
- POJ3159——Candies
- poj3159 Candies 2012-09-07
- POJ 3159 Candies 差分约束dij
- POJ 3159 Candies(差分约束系统 spfa+stack)
- POJ 3159 Candies(SPFA+栈)差分约束
- POJ-3159 Candies
- poj 3159 -- Candies ( spfa + 栈 )
- POJ 3159 Candies(差分约束)
- POJ 3159 Candies
- POJ 3159 Candies (差分约束 Dijkstra+优先队列 SPFA+栈)
- poj 3159 Candies 差分约束+SPFA+栈优化
- [poj 3159]Candies[差分约束详解][朴素的考虑法]
- [差分约束]POJ 3159——Candies
- POJ 3159 Candies(差分约束 转spfa+stack 求最短路径)
- POJ 3159 Candies(差分约束,最短路)
- POJ 3159 Candies(dijkstra+heap&spfa+stack)
- poj 3159 Candies