http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2031

题目大意:

给定一个n个点m条边的加权有向图,求平均权值最小的回路。

思路:

用二分法求解。假设答案为mid,只需要判断是否存在平均值小于Mid的回路。怎么判断呢?假设一个包含k条边的回路,回路上各条边的权值为w1,w2……wk,那么平均值小于mid意味着 w1+w2+……wk< k* mid即:

(w1-mid)+(w2-mid)+……(wk-mid)<0

换句话说,只要把图中没一条边a,b的权值w(a,b)变为w(a,b)-mid,在判断图中有没有负权回路。

怎么判断负权回路呢?这就是SPFA的用法了,一个顶点入队列超过n次,就表示有回路。

记住这个不一定是联通的图。所以一开始要把所有的点加入队列。WA找了半天看了别人代码才发现。

---------------2014/01/26----------

想起可以增加一个点0,从该点到所有点的权值为0,那么可以保证改图连通,并且不会破坏负环~~~~~~

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=52;
const int INF=100000000;
struct edge
{
int to;
double val;
int next;
}e[MAXN*MAXN]; int head[MAXN],len,n,m;
void add(int from,int to,double val)
{
e[len].to=to;
e[len].val=val;
e[len].next=head[from];
head[from]=len++;
} bool spfa()
{
double dis[MAXN];
bool vis[MAXN]={0};
int cnt[MAXN]={0};
queue<int> q;
for(int i=1;i<=n;i++) //图可能是非联通的,所以一开始要把全部加入。WA在这里
dis[i]=INF; q.push(0);
vis[0]=cnt[0]=1;
dis[0]=0; while(!q.empty())
{
int cur=q.front();
q.pop();
vis[cur]=false;
for(int i=head[cur];i!=-1;i=e[i].next)
{
int id=e[i].to;
if(dis[cur] + e[i].val < dis[id])
{
dis[id]=dis[cur]+e[i].val;
if(!vis[id])
{
cnt[id]++;
vis[id]=true;
q.push(id);
if(cnt[cur] > n)
return true;
}
}
}
}
return false;
} void change(double x)
{
for(int k=1;k<=n;k++)
for(int i=head[k];i!=-1;i=e[i].next)
e[i].val+=x;
}
bool test(double x)
{
change(-x);
bool ok=spfa();
change(x);
return ok;
} int main()
{
int T;
scanf("%d",&T);
for(int ri=1;ri<=T;ri++)
{
len=0;
memset(head,-1,sizeof(head));
double L=INF,R=0;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int from,to;
double val;
scanf("%d%d%lf",&from,&to,&val);
if(R< val)
R=val;
if(L > val)
L=val;
add(from,to,val);
}
for(int i=1;i<=n;i++)
add(0,i,0); printf("Case #%d: ",ri);
if(!test(R+1))
{
printf("No cycle found.\n");
continue;
} while(R-L > 1e-3) //浮点数判断大小要这样
{
double mid = L + (R-L)/2;
if(test(mid))
R = mid;
else
L = mid;
}
printf("%.2lf\n",R);
} return 0;
}

一开始全部加入队列版本

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=52;
const int INF=100000000;
struct edge
{
int to;
double val;
int next;
}e[MAXN*MAXN]; int head[MAXN],len,n,m;
void add(int from,int to,double val)
{
e[len].to=to;
e[len].val=val;
e[len].next=head[from];
head[from]=len++;
} bool spfa()
{
double dis[MAXN];
bool vis[MAXN];
int cnt[MAXN];
queue<int> q;
for(int i=1;i<=n;i++) //图可能是非联通的,所以一开始要把全部加入。WA在这里
{
dis[i]=INF;
vis[i]=true;
cnt[i]=1;
q.push(i);
} while(!q.empty())
{
int cur=q.front();
q.pop();
vis[cur]=false; for(int i=head[cur];i!=-1;i=e[i].next)
{
int id=e[i].to;
if(dis[cur] + e[i].val < dis[id])
{
dis[id]=dis[cur]+e[i].val;
if(!vis[id])
{
cnt[id]++;
vis[id]=true;
q.push(id);
if(cnt[cur] > n)
return true;
}
}
}
}
return false;
} void change(double x)
{
for(int k=1;k<=n;k++)
for(int i=head[k];i!=-1;i=e[i].next)
e[i].val+=x;
}
bool test(double x)
{
change(-x);
bool ok=spfa();
change(x);
return ok;
} int main()
{
int T;
scanf("%d",&T);
for(int ri=1;ri<=T;ri++)
{
len=0;
memset(head,-1,sizeof(head));
double L=INF,R=0;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int from,to;
double val;
scanf("%d%d%lf",&from,&to,&val);
if(R< val)
R=val;
if(L > val)
L=val;
add(from,to,val);
}
printf("Case #%d: ",ri);
if(!test(R+1))
{
printf("No cycle found.\n");
continue;
} while(R-L > 1e-3) //浮点数判断大小要这样
{
double mid = L + (R-L)/2;
if(test(mid))
R = mid;
else
L = mid;
}
printf("%.2lf\n",R);
} return 0;
}

UVA 11090 - Going in Cycle!! SPFA的更多相关文章

  1. UVA 11090 Going in Cycle!! SPFA判断负环+二分

    原题链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...

  2. UVA - 11090 - Going in Cycle!!(二分+差分约束系统)

    Problem  UVA - 11090 - Going in Cycle!! Time Limit: 3000 mSec Problem Description You are given a we ...

  3. UVA 11090 - Going in Cycle!!(Bellman-Ford)

    UVA 11090 - Going in Cycle!! option=com_onlinejudge&Itemid=8&page=show_problem&category= ...

  4. UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)

    题意: 给定一个n个点m条边的带权有向图,求平均权值最小的回路的平均权值? 思路: 首先,图中得有环的存在才有解,其次再解决这个最小平均权值为多少.一般这种就是二分猜平均权值了,因为环在哪也难以找出来 ...

  5. UVA 11090 : Going in Cycle!! 【spfa】

    题目链接 题意及题解参见lrj训练指南 #include<bits/stdc++.h> using namespace std; const double INF=1e18; ; ; in ...

  6. UVa 11090 Going in Cycle!!【Bellman_Ford】

    题意:给出n个点m条边的加权有向图,求平均值最小的回路 自己想的是用DFS找环(真是too young),在比较找到各个环的平均权值,可是代码实现不了,觉得又不太对 后来看书= =好巧妙的办法, 使用 ...

  7. UVA 11090 Going in Cycle!!(二分答案+判负环)

    在加权有向图中求平均权值最小的回路. 一上手没有思路,看到“回路”,第一想法就是找连通分量,可又是加权图,没什么好思路,那就转换题意:由求回路权值->判负环,求最小值->常用二分答案. 二 ...

  8. UVA 11090 Going in Cycle!!

    要求给定的图的中平均权值最小的环,注意处理自环的情况就能过了. 按照w1+w2+w3+….wn < n*ave的不等式,也就是(w1-ave) + (w2-ave) +…..(wn-ave) & ...

  9. UVa 11090 Going in Cycle!! (Bellman_Ford)

    题意:给定一个加权有向图,求平均权值最小的回路. 析:先十分答案,假设答案是 ans,那么有这么一个回路,w1+w2+w3+...+wk < k*ans,这样就是答案太大,然后移项可得,(w1- ...

随机推荐

  1. Linux平台下Ntop流量监测安装,并实现Netflow全过程

    Linux平台下Ntop流量监测安装,并实现Netflow全过程 更多原创教学视频详见: http://you.video.sina.com.cn/m/1443650204 本文出自 "李晨 ...

  2. vuejs模板中使用html代码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Node.js REPL(交互式解析器)

    Node.js REPL(交互式解释器) Node 自带了交互式解释器,可以执行以下任务: 读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中. 执行 - 执行输入的数据结 ...

  4. Easy mock - 安装配置和基本使用

    Easy-mock easy-mock是一款比较好用的接口模拟工具, 使用之前我们需要安装和配置 需要下载的内容有以下 Node Redis MongoDB Node和Redis一路点下一步就行, M ...

  5. 【Pycharm】【HTML】注释问题

    学习HTML中,遇到的注释前存在空行的问题: 只要找到Pycharm设置中:勾选去掉即可

  6. 【习题 8-10 UVA - 1614】Hell on the Markets

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 证明:前i个数一定能凑够1..sum[i]中的所有数字 i=1时显然成立. 现在假设i>=2时结论成立 即前i个数字能凑出1. ...

  7. Spring Cloud Sleuth通过Kafka将链路追踪日志输出到ELK

    1.工程简介 elk-eureka-server作为其他三个项目的服务注册中心 elk-kafka-client调用elk-kafka-server,elk-kafka-server再调用elk-ka ...

  8. 软考之路--从生活着手,看PV怎样操作

    PV操作.是软考其中一个非常重要的考点,一听到这个名词,顿时赶脚高大上有么有,在软考的历年试题中,也不乏PV操作的身影,老师也对PV操作进行了一次讲课,那时年少.听得稀里糊涂,也不是非常理解,在小编的 ...

  9. linux中内存泄漏的检測(五)记录内存泄漏的代码

    到眼下为止,先后通过wrap malloc.new函数重载和计算指针内存大小的方法.基本上满足了对内存泄漏检測的须要. 假设发现了内存泄漏.那么就要找到内存泄漏的地方而且修正它了. 茫茫代码.如何去找 ...

  10. values-dimen 不同分辨率资源实现引用

    今天遇到了一种情况,就是在不同分辨率下面出现了需要设定不同的距离,当时第一反映就是重新定义一个layout.但是,仅仅为了更改一个数值就复制那么多的代码,明显不合里.后来就想到干脆在不同的分辨率下创建 ...