Word Rings POJ2949 (Bellman-ford算法,找平均值最大的环)
来源:互联网 发布:皇室战争电磁炮数据 编辑:程序博客网 时间:2024/04/30 15:24
题意本身比较简单,就是找一个平均值最大的环。
在做这个题之前,我们先解决一个问题,如何找到一个平均值最小的环。
设有一个环中,有k 个点,那么这个环的平均权值X是:
X=(w1+w2+w3+,..,,,wk)/k
然后我们把k乘过去:(w1+w2+…..wk)=kX
Bellman_ford算法的一个重要作用是判断负圈,所以这个题可以利用这个特点来做。
再把(w1+w2+…..wk)=kX处理一下。
就是(w1-X)+(w2-X)+(w3-X)+(w4-X)+…+(wk-X)=0
把这个等号改成小于号:(w1-X)+(w2-X)+(w3-X)+(w4-X)+…+(wk-X)<0
所以我们首先二分这个X,把所有的边权减去X,如果说有平均权值为X的,必定会出现:
(w1-X)+(w2-X)+(w3-X)+(w4-X)+…+(wk-X)=0(w1…wk都是那个环里的点)
所以让这个X稍微大一点点,就会出现负圈了。
由于如果X很大很大的话,也可以产生这个现象。
所以我们要找的X,就是那个刚好使得有这个式子产生的,最小的这个值。
这个值就是 最小的环的平均值(确切的说比平均值稍微大一点点,这里是精度问题了)。
这个题不一样的地方在于,是求最大的,所以我们需要改变一下。
把图中所有的边改成C-w(其中C是一个大于所有w的数字,注意不要溢出)。
再在这个新图里面去找最小的平均值。
就变成了 (C-w1-X)+(C-w2-X)+(C-w3-X)+(C-w4-X)+…+(C-wk-X)=0
然后把这个式子变成了
C-X=(w1+w2.+w3+…+wk)/K
C-X就是新图里最小的平均值。
如果要C-X越小,就意味着X要越大。
所以C-X最小,就意味着X最大。
这个题就这样做出来了。
细节:
①double不可以直接比大小,要写一个eps量,这里我写了1e-3, 连1e-2都会WA的。。
②所有单词,前两个字母所表示的点的dis都是0,然后再跑Bellman-ford。
#include<iostream>#include<string.h>#include<string>#include<algorithm>#include<stdio.h>#include<map>#include<vector>using namespace std;double eps=1e-3;const double alpha=1001;bool ashead[120000];double dis[120000];map<string,int> mp;struct Edge{ int from,to; double w;};vector<Edge> E;int n;char input[1200];void init(){ memset(ashead,0,sizeof(ashead)); mp.clear(); E.clear();}bool Bellman_ford(double mid){ for(int i=0;i<120000;i++) dis[i]=1e9; int size=E.size(); dis[0]=0; for(int i=0;i<size;i++) { if(E[i].from==0) { dis[E[i].to]=0; continue; } E[i].w-=mid; //cout<<E[i].w<<endl; } int cnt=mp.size(); for(int i=1;i<=cnt;i++) { for(int j=0;j<size;j++) { int from=E[j].from; int to=E[j].to; double w=E[j].w; if(dis[to]-(dis[from]+w)>eps) { dis[to]=dis[from]+w; //cout<<dis[to]<<endl; } } } bool can=true; for(int j=0;j<size;j++) { int from=E[j].from; int to=E[j].to; double w=E[j].w; //cout<<dis[from]<<" "<<dis[to]<<" "<<w<<endl; if(dis[to]-(dis[from]+w)>eps) { //cout<<"fuck"<<endl; can=false; } } for(int i=0;i<size;i++) { if(E[i].from==0) continue; E[i].w+=mid; } return can;}int main(){ while(cin>>n) { if(n==0) break; init(); int cnt=1; for(int i=1;i<=n;i++) { scanf("%s",input); int len=strlen(input); if(len<2) continue;//以防万一吧。。。 string temp1; temp1+=input[0]; temp1+=input[1]; if(mp[temp1]==0) mp[temp1]=cnt++; string temp2; //temp.clear(); temp2+=input[len-2]; temp2+=input[len-1]; if(mp[temp2]==0) mp[temp2]=cnt++; Edge ts; ts.from=mp[temp1]; ts.to=mp[temp2]; ts.w=alpha-len; E.push_back(ts); if(ashead[mp[temp1]]==0) { Edge tt; tt.from=0; tt.to=mp[temp1]; tt.w=0; E.push_back(tt); ashead[mp[temp1]]=1; } } double ans=0x3f3f3f3f; double l=0; double r=1200; //cout<<mp.size()<<endl; while(r-l>eps) { double mid=(l+r)/2; //cout<<mid<<endl; if(Bellman_ford(mid)==false)//有负圈 { ans=min(mid,ans); r=mid; } else l=mid; } //cout<<ans<<endl; if(ans==0x3f3f3f3f) printf("No solution.\n"); else { ans=alpha-ans; printf("%.2lf\n",ans); } } return 0;}
- Word Rings POJ2949 (Bellman-ford算法,找平均值最大的环)
- poj2949-Word Rings
- poj2949 Word Rings(建图+二分答案+spfa判正环)
- Bellman-Ford算法 的认识
- Bellman-Ford算法的详解
- Bellman-Ford算法的实现
- bellman-Ford 算法(转)
- bellman-ford算法的优化spfa算法
- Bellman-Ford算法的改进:SPFA算法
- SPFA算法 (基于Bellman-Ford算法)
- uva 558 Wormholes (Bellman-Ford算法判断负环)
- 求单源最短路径的算法(Bellman-Ford)
- poj_1860 Bellman-Ford算法的逆向应用
- Bellman-Ford判断有负环的算法模板
- 图的单源最短路径Bellman-Ford算法
- 单源最短路径的Bellman-Ford算法。
- Bellman-Ford算法的队列优化
- 关于Bellman-Ford算法的理解
- 第九天:JAVA中的多态,抽象类和接口
- Maven项目中,将普通工程修改为web工程办法
- Error:Unable to start the daemon process.解决
- FPGA学习:VHDL设计灵活性&不同设计思路比较
- Smarty模板技术-自定义函数-1
- Word Rings POJ2949 (Bellman-ford算法,找平均值最大的环)
- centOS7开机直接进入命令界面
- 简单排序(1)
- 我的见解之hibernate(三)
- php之static后期绑定/延迟绑定
- 我的博客
- 三种经典的递归-java
- RedisCluster 安装
- hadoop2