UVA 11090 - Going in Cycle!! SPFA
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的更多相关文章
- UVA 11090 Going in Cycle!! SPFA判断负环+二分
原题链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- UVA - 11090 - Going in Cycle!!(二分+差分约束系统)
Problem UVA - 11090 - Going in Cycle!! Time Limit: 3000 mSec Problem Description You are given a we ...
- UVA 11090 - Going in Cycle!!(Bellman-Ford)
UVA 11090 - Going in Cycle!! option=com_onlinejudge&Itemid=8&page=show_problem&category= ...
- UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
题意: 给定一个n个点m条边的带权有向图,求平均权值最小的回路的平均权值? 思路: 首先,图中得有环的存在才有解,其次再解决这个最小平均权值为多少.一般这种就是二分猜平均权值了,因为环在哪也难以找出来 ...
- UVA 11090 : Going in Cycle!! 【spfa】
题目链接 题意及题解参见lrj训练指南 #include<bits/stdc++.h> using namespace std; const double INF=1e18; ; ; in ...
- UVa 11090 Going in Cycle!!【Bellman_Ford】
题意:给出n个点m条边的加权有向图,求平均值最小的回路 自己想的是用DFS找环(真是too young),在比较找到各个环的平均权值,可是代码实现不了,觉得又不太对 后来看书= =好巧妙的办法, 使用 ...
- UVA 11090 Going in Cycle!!(二分答案+判负环)
在加权有向图中求平均权值最小的回路. 一上手没有思路,看到“回路”,第一想法就是找连通分量,可又是加权图,没什么好思路,那就转换题意:由求回路权值->判负环,求最小值->常用二分答案. 二 ...
- UVA 11090 Going in Cycle!!
要求给定的图的中平均权值最小的环,注意处理自环的情况就能过了. 按照w1+w2+w3+….wn < n*ave的不等式,也就是(w1-ave) + (w2-ave) +…..(wn-ave) & ...
- UVa 11090 Going in Cycle!! (Bellman_Ford)
题意:给定一个加权有向图,求平均权值最小的回路. 析:先十分答案,假设答案是 ans,那么有这么一个回路,w1+w2+w3+...+wk < k*ans,这样就是答案太大,然后移项可得,(w1- ...
随机推荐
- The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
https://stackoverflow.com/questions/30045871/sorting-the-view-based-on-frequency-in-sql-server Just ...
- js防止提交数据之后的按钮连击
js防止提交数据之后的按钮连击 一.实例描述 当页面提交的数据特别多时,页面会反应比较迟钝,此时如果用户等不及而连续单击按钮,导致数据重复提交.本案例就是为了防止数据重复提交. 二.截图 三.代码 & ...
- ElasticSearch 5.2.2 集群环境的搭建
在之前 ElasticSearch 搭建好之后,我们通过 elasticsearch-header 插件在查看 ES 服务的时候,发现 cluster-health 显示的是 YELLOW. Why? ...
- umask---默认权限掩码
- Objective-C ,ios,iphone开发基础:UIAlertView使用详解
UIAlertView使用详解 Ios中为我们提供了一个用来弹出提示框的类 UIAlertView,他类似于javascript中的alert 和c#中的MessageBox(); UIAlertVi ...
- 洛谷 P2105 K皇后
P2105 K皇后 题目描述 小Z最近捡到了一个棋盘,他想在棋盘上摆放K个皇后.他想知道在他摆完这K个皇后之后,棋盘上还有多少了格子是不会被攻击到的. (Ps:一个皇后会攻击到这个皇后所在的那一行,那 ...
- ViewPager 入门一
使用ViewPager能够得到不同view的切换效果 例如以下图,实现了四个view间的相互滑动 一.新建项目,引入ViewPager控件 ViewPager.它是google SDk中自带的一个附加 ...
- 图片裁剪的js有哪些(整理)
图片裁剪的js有哪些(整理) 一.总结 一句话总结:如果用了amaze框架就去amaze框架的插件库里面找图片裁剪插件,如果没用,jcrop和cropper都不错. 1.amazeui的插件库中有很多 ...
- 洛谷P2660 zzc 种田
题目背景 可能以后 zzc就去种田了. 题目描述 田地是一个巨大的矩形,然而zzc 每次只能种一个正方形,而每种一个正方形时zzc所花的体力值是正方形的周长,种过的田不可以再种,zzc很懒还要节约体力 ...
- 如何使用Linux套接字?
我们知道许多应用程序,例如E-mail.Web和即时通信都依靠网络才能实现.这些应用程序中的每一个都依赖一种特定的网络协议,但每个协议都使用相同的常规网络传输方法.许多人都没有意识到网络协 ...