spfa算法的优化及应用 poj 2949
来源:互联网 发布:excel跨工作簿引用数据 编辑:程序博客网 时间:2024/05/21 08:37
这道题综合了两种常见的问题:字符串的接龙以及平均值的最优化问题。对于前者,我们可以采取把单词看成边,把首尾字母组合看成点的方法。例如对于单词ababc就是点”ab”向点”bc”连一条长度为5的边。这样问题的模型变得更加清晰,规模也得到减小。那么原问题就可以转化成在此图中找一个环,使得环上边权的平均值最大。对于这种问题,我们有很经典的解决方法:
由于Average=(E1+E2+…..+Ek)/K
所以Average*K=E1+E2+……+Ek
即(E1-Average)+(E2-Average)+….+ (Ek-Average)=0
另外注意到上式中的等于号可以改写为小于等于,那么我们可以二分答案Ans,然后判断是否存在一组解满足(E1+E2+…..+Ek)/K>Ans,即判断
(E1- Ans)+(E2- Ans)+….+ (Ek- Ans)>0
于是在二分答案后,我们把边的权值更新,问题就变成了查找图中是否存在一个正环。
以上摘自国家队论文《spfa算法的优化及应用》
知道了以上方法后,主要要解决的问题就是如何找环了
在试了论文中的多种优化方法后,最终还是臣服于将spfa写成dfs,直接将2000ms的代码加速到了200ms,太匪夷所思了
仔细思考后发现,当spfa在解决最短路径问题时用bfs或者dfs区别可能不大(但有的题目的数据比较刁钻,用可能用dfs(栈)更加高效)
但是在需要找环的时候,dfs的做法变的非常高效,直接从最近被更新的点出发继续松弛操作,很快就可以找到环了
也不用等到入队超过n次才判断出现环
最快冲到了235ms,这已经是我的极限了,虽然没挤进第一版,不过还是收获蛮大,对一个算法的优化永远都没有止境
以下是2000多ms的算法
#include<cstdio>#include<map>#include<queue>#include<stack>#include<cstring>#include<algorithm>using namespace std;const int N = 1010;const int M = 100010;const double eps = 1e-3;const double inf = 1000000000;struct EDGE{ int v,next; double w;}edge[M],TE[M];int head[N];int E,tot;stack<int> ST;void add_edge(int a,int b,double w){ edge[E].v=b; edge[E].w=w; edge[E].next=head[a]; head[a]=E++;}bool vis[N];double dis[N];int in[N];bool PC;//正环double MaxEdge;void spfa(double aver,int n){ while(!ST.empty()) ST.pop(); fill(vis,vis+n+1,false); fill(dis,dis+n+1,0); fill(in,in+n+1,0); for(int i=1;i<=n;i++) ST.push(i),vis[i]=true; while(!ST.empty()){ int u=ST.top();ST.pop();vis[u]=false; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(dis[u]+edge[i].w-aver>dis[v]){ dis[v]=dis[u]+edge[i].w-aver; if(dis[v]>MaxEdge){ PC=true;return ;} if(!vis[v]){ vis[v]=true; ST.push(v); in[v]++; if(in[v]>n+1){ PC=true; return ; } } } }//end of for }// end of while }bool solve(double aver){ PC=false; spfa(aver,tot); return PC;}char s[M];int flag[3010];int main(){ int n; while(scanf("%d",&n),n){ E=0;tot=0;MaxEdge=0; memset(head,-1,sizeof(head)); fill(flag,flag+3000,0); for(int i=0;i<n;i++){ scanf("%s",s); int len=strlen(s); if(len>MaxEdge) MaxEdge=len; int a=(s[0]-'a')*26+s[1]-'a'; int b=(s[len-2]-'a')*26+s[len-1]-'a'; if(!flag[a]) flag[a]=++tot; int id1=flag[a]; if(!flag[b]) flag[b]=++tot; int id2=flag[b]; add_edge(id1,id2,(double)len); } MaxEdge*=n; double l=0,r=1000,best=-1,mid; while(l+eps<=r){ mid=(l+r)/2; if(solve(mid)){ best=mid; l=mid; } else r=mid; } if(best!=-1) printf("%.3lf\n",best); else printf("No solution.\n"); } return 0;}
下面是200多ms的算法
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N = 677;const int M = 100010;const double eps = 1e-3;const double inf = 1000000000;struct EDGE{ int v,next; double w;}edge[M],TE[M];int head[N],E,tot;void add_edge(int a,int b,double w){ edge[E].v=b; edge[E].w=w; edge[E].next=head[a]; head[a]=E++;}int vis[N];double dis[N];int in[N];bool PC;//正环double MaxEdge,aver;void spfa(int u,int h,double aver){ if(PC) return ; vis[u]=h; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(dis[u]+edge[i].w-aver>dis[v]){ dis[v]=edge[i].w+dis[u]-aver; if(dis[v]>MaxEdge) {PC=true;return ;} if(!vis[v]) spfa(v,h,aver);if(PC) return ; else if(vis[v]==h){ PC=true; return ; } } } vis[u]=0;}bool solve(double aver){ PC=false; fill(dis,dis+tot+1,0); fill(vis,vis+tot+1,0); for(int i=1;i<=tot;i++){ spfa(i,i,aver); if(PC) break; } return PC;}char s[M];int flag[800];int main(){ int n; while(scanf("%d",&n),n){ E=0;tot=0;MaxEdge=0; fill(head,head+700,-1); fill(flag,flag+700,0); for(int i=0;i<n;i++){ scanf("%s",s); int len=strlen(s); if(len>MaxEdge) MaxEdge=len; int a=(s[0]-'a')*26+s[1]-'a'; int b=(s[len-2]-'a')*26+s[len-1]-'a'; if(!flag[a]) flag[a]=++tot; int id1=flag[a]; if(!flag[b]) flag[b]=++tot; int id2=flag[b]; add_edge(id1,id2,(double)len); } MaxEdge*=n; double l=0,r=1000,best=-1,mid; while(l+eps<r){ mid=(l+r)/2; if(solve(mid)){ best=mid; l=mid; } else r=mid; } if(best!=-1) printf("%.3f\n",best); else printf("No solution.\n"); } return 0;}
- spfa算法的优化及应用 poj 2949
- spfa算法的一些优化
- SPFA算法的两个优化
- SPFA算法及前向星优化
- SPFA算法及前向星优化
- bellman-ford算法的优化spfa算法
- spfa算法(FIFO优化的BellmanFord算法)
- spfa的SLF 和 LLL优化算法
- SPFA算法 Bellman_ford优化
- poj 1860 spfa算法
- SPFA算法 poj 1364
- SPFA算法的基础变形应用
- Candies POJ 3159 (堆优化的SPFA,)
- 总结一下最短路径的贝尔曼-福特算法(Bellman-Ford)及用队列优化(spfa)
- 总结一下最短路径的贝尔曼-福特算法(Bellman-Ford)及用队列优化(spfa)
- POJ 1511 Invitation Cards 【最短路,spfa算法,Dijkstra算法堆优化】
- SPFA算法 poj 1201Intervals
- poj 3159 Candies------spfa算法
- codeforces 127 201C 双向DP
- poj 2831 次小生成树
- hdu 1421 经典DP
- zoj 3527 带环的树形DP
- zoj 3475 最小割 巧妙建图
- spfa算法的优化及应用 poj 2949
- zoj 3164 分组背包 + 各种背包
- codeforces 154 A DP
- python dictionary
- android用异步操作AsyncTask编写文件查看器
- 我国第三方支付交易市场发展现状调查解析
- python list
- 网络性能优化(NAPI)
- Codeforces Round #137 (Div. 2) / 222A Shooshuns and Sequence (模拟)