H - Going in Cycle!! (UVA - 11090)
- 题目大意
给你一个有向图,问你定义一个环的平均值为这个环上所有边的平均值,问你最小的环的平均值是多少。
- 解题思路
先利用spfa来判断负环,然后用二分去判断若当前的二分值是mid,让所有的边都减去这个值,如果此时图中出现负环,则说明有环的平均值比这个更小。
- 代码
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N=500;
const int M=1e6+5;
const int INF=0x3f3f3f;
int n,m;
struct edge {
int v,next;
double w;
}e[M*2];
int head[N], cnt;
double d[N];
int inq[N];
int cn[N];
void init ()
{
cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,double c)
{
e[cnt].w=c;
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
bool SPFA(int s) {
memset(d, INF, sizeof(d));
memset(inq, 0, sizeof(inq));
memset(cn, 0, sizeof(cn));
queue<int> Q;
Q.push(s);
d[s] = 0;
inq[s] = 1;
while(Q.size()) {
int u = Q.front();
Q.pop();
inq[u] = 0;
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
double w = e[i].w;
if(d[v] > d[u] + w)
{
d[v] = d[u] + w;
if(!inq[v])
{
Q.push(v);
inq[v] = 1;
if(++cn[v] >= n)
return false;
}
}
}
}
return true;
}
bool check(double x)
{
bool vis=false;
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
e[j].w-=x;
}
for(int i=1;i<=n;i++)
{
if(!SPFA(i))
vis=true;
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
e[j].w+=x;
}
return vis;
}
int main()
{
int t,a,b;
double c;
scanf("%d",&t);
for(int k=1;k<=t;k++)
{
double l=INF,r=0,mid;
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%lf",&a,&b,&c);
addedge(a,b,c);
l=min(l,c);
r=max(r,c);
}
printf("Case #%d: ",k);
if(!check(r+1))
printf("No cycle found.\n");
else
{
while(r-l>1e-8)
{
mid=(r+l)/2;
if(check(mid))
r=mid;
else
l=mid;
}
printf("%.2lf\n",r);
}
}
return 0;
}

浙公网安备 33010602011771号