今天第一次系统的学习了一下最短路算法,开始刷第十一章,第一次写Dijkstra算法,出现了很多喜闻乐见的错误。。而且uva上样例很水,瓢虫也很水 ,坑了我好久。
首先是对于结点的处理,我们必须要维护一个二元组,一个表示结点一个表示当前结点最短路。 因为Dijkstra算法利用了优先队列来加速算法,所以需要定义小于运算符,一开始我直接将状态装进了优先队列,显然是不对的,因为优先队列的作用就是取出当前距离最短的结点。
其次,说说最短路算法蕴含的巧妙思想: 每次从当前所有还未标记的结点中选择一个距离最小的点,从这个点更新与之相连的所有结点 。重复此过程 。
为什么这样做是正确的呢? 百度百科上又一个动态图可以帮助我们很好的理解这个过程 。传送门:点击打开链接
该题是一个很巧妙的最短路问题,需要我们把模型抽象出来,看清楚要解决的问题的实质是什么。
将状态集合当做结点,将所花费的时间当做边的权值,两个“结点”是否相连取决于第一个字符串与该结点的关系! 真是好题 ~
另外一点,用动态规划进行状态转移时很重要的一点是不能转移到以前的状态,即状态图不是DAG,所以不能用记忆化搜索 。
细节参见代码:
#include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 22; const int maxm = 105; int n,m,kase = 0,ok = 0 ,d[1<<maxn],done[1<<maxn]; struct node{ int t; char a[maxn],b[maxn]; }pat[maxm]; struct Node{ int bugs,dist; bool operator < (const Node& v) const { return dist > v.dist; } }; int dijkstra() { priority_queue<Node> q; for(int i=0;i<(1<<n);i++) { done[i] = 0; d[i] = INF; } Node u; u.dist = 0; u.bugs = (1<<n)-1; d[u.bugs] = 0; q.push(u); while(!q.empty()) { Node u = q.top(); q.pop(); if(u.bugs == 0) return u.dist; if(done[u.bugs]) continue; done[u.bugs] = true; for(int i=1;i<=m;i++) { bool ok = true; for(int j=0;j<n;j++) { //检查该结点是否可以连一条边 if(pat[i].a[j] == '-' && u.bugs & (1<<j)) { ok = false; break; } if(pat[i].a[j] == '+' && !(u.bugs & (1<<j))) { ok = false; break; } } if(ok) { Node v = u ; for(int j=0;j<n;j++) { //更新找到下一个结点 if(pat[i].b[j] == '-') { v.bugs &= ~(1<<j); } else if(pat[i].b[j] == '+') { v.bugs |= (1<<j); } } if(d[v.bugs] > u.dist + pat[i].t) { d[v.bugs] = u.dist + pat[i].t; v.dist = d[v.bugs]; q.push(v); } } } } return -1; } int main() { while(~scanf("%d%d",&n,&m)) { if( !n && !m ) return 0; for(int i=1;i<=m;i++) { scanf("%d%s%s",&pat[i].t,pat[i].a,pat[i].b); } int ans = dijkstra(); printf("Product %d\n",++kase); if(ans < 0) printf("Bugs cannot be fixed.\n\n"); else printf("Fastest sequence takes %d seconds.\n\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
658 - It's not a Bug, it's a Feature! (Dijkstra算法)
时间: 2024-11-03 03:33:49