题目链接:UVA 11090
解题思路:
这题需要使用二分法来解决,思路类似与最大值最小化问题,我们可以把求解最小均值环的问题转化成判断负环的问题。二分的过程中,我们可以每次猜想一个最小值,然后使所有的边的权值减去这个最小值,若存在负环,则这个值太大了,最小值需要减小,否则增加。判断负环可以使用Bellman-Ford算法的优化算法,SPFA算法解决。
代码设计:
因为最小均值可以为浮点数,而且只需要保留两位小数,为了保证精度,可以把浮点数问题转换成整数来做,即所有权值乘1000;另外判负环的SPFA写法可以在原来的单源最短路代码上进行改进,即一开始将所有最短距离设为0,并且所有结点入队。
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 55
using namespace std;
int n,m,len,inque[maxn],cnt[maxn],head[maxn];
long long d[maxn];
struct Edge{
int v,next;
long long w;
}e[maxn*maxn];
void init()
{
len=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,long long w){
e[len].v=v,e[len].w=w,e[len].next=head[u];
head[u]=len++;
}
bool spfa()
{
memset(cnt,0,sizeof(cnt));
memset(inque,0,sizeof(inque));
stack<int> s;
for(int start=1;start<=n;start++)
d[start]=0,inque[start]=1,cnt[start]++,s.push(start);
while(!s.empty())
{
int tmp=s.top();
s.pop(), inque[tmp]=0;
for(int i=head[tmp];i!=-1;i=e[i].next)
{
int index=e[i].v;
long long w=e[i].w;
if(d[index]>d[tmp]+w)
{
d[index]=d[tmp]+w;
if(!inque[index])
{
inque[index]=1, s.push(index), cnt[index]++;
if(cnt[index]>n)
{
return 0;
}
}
}
}
}
return 1;
}
bool solve(long long num)
{
for(int i=0;i<len;i++)
e[i].w-=num;
bool flag=!spfa();
for(int i=0;i<len;i++)
e[i].w+=num;
return flag;
}
int main()
{
int T,t=1;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d %d",&n,&m);
int u,v;
long long w,maxw=0;
len=0;
for(int i=0;i<m;i++)
{
scanf("%d %d %lld",&u,&v,&w);
addEdge(u,v,1000*w);
maxw=max(maxw,1000*w);
}
printf("Case #%d: ",t++);
if(!solve(maxw+1))
{
printf("No cycle found.\n");
}
else
{
long long low=0,high=maxw;
while(high>low)
{
long long mid=(low+high)/2+1;
if(solve(mid))
high=mid-1;
else
low=mid;
}
printf("%.2lf\n",double(low)/1000);
}
}
return 0;
}
改进版SPFA判负环:
bool spfa()
{
queue<int> s;
for(int start=1;start<=n;start++)
d[start]=0,inque[start]=1,cnt[start]=1,s.push(start);
while(!s.empty())
{
int tmp=s.front();
s.pop(), inque[tmp]=0;
for(int i=head[tmp];i!=-1;i=e[i].next)
{
int index=e[i].v;
double w=e[i].w;
if(d[index]>d[tmp]+w)
{
d[index]=d[tmp]+w;
if(!inque[index])
{
inque[index]=1, s.push(index), cnt[index]++;
if(cnt[index]>n)
{
return 0;
}
}
}
}
}
return 1;
}