uva11090 Going in Cycle!!题解(负环)

31 篇文章 0 订阅
23 篇文章 0 订阅

本来以为是Floyd求最小环的模板题,然而,然而,似乎不是。但其实这道题求的是边权平均值最小的环,所以貌似不能用Floyd,因为它不一定能遍历
图中所有的环,多么痛的领悟,一个晚上,调不出来。
也或许是我姿势不对。(代码在最后面,有大神能指出我错在哪里,必万分感谢)
正确做法:二分+SPFA
二分答案,将所有边权减去二分的那个值,然后spfa判断是否有负环,
如果存在负环说明当前值太大了,r=mid;
如果不存在负环说明当前值太小了,l=mid;

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=59;
const int INF=0x3f3f3f3f;
const double eps=1e-6;
int dt[MAXN][MAXN],cnt[MAXN],n,m;
double d[MAXN];
bool vs[MAXN];
bool SPFA(int beg,double cut)
{
    ms(vs);
    for(int i=1;i<=n;i++) d[i]=1e14;
    vs[beg]=true;
    d[beg]=0;
    queue<int> que;
    while(!que.empty()) que.pop();
    que.push(beg);
    ms(cnt);
    cnt[beg]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vs[u]=false;
        for(int j=1;j<=n;j++)
        {
            if(dt[u][j]==INF) continue;
            if(d[j]>d[u]+dt[u][j]-cut){
                d[j]=d[u]+dt[u][j]-cut;
                if(!vs[j]) {
                    if(++cnt[j]>n) return false;
                    vs[j]=true;
                    que.push(j);
                }
            }
        }
    }
    return true;
}
int main(int argc, char const *argv[])
{
    int N,ti=0;
    cin>>N;
    while(++ti<=N){
        scanf("%d %d",&n,&m);
        int maxw=0;
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
              dt[j][i]=dt[i][j]=INF;//d[i][i]应该是INF,而不是0
        while(m--){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            maxw=max(maxw,w);
            dt[u][v]=min(w,dt[u][v]);
        }
        double l=0.0,r=maxw+2.0;
        while(r-l>eps){
            double mid=(l+r)*0.5;
            bool flg=false;
            for(int i=1;i<=n;i++)
                if(!SPFA(i,mid)) {flg=true;break;}
            if(flg) r=mid;
            else l=mid;
        }
        printf("Case #%d: ",ti );
        if(r>maxw+1.0) puts("No cycle found.");//不要写r>maxw,精度啊=。=|||
        else printf("%.2f\n",r );
    }
    return 0;
}

wa到死的Floyd

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=59;
const int INF=0x3f3f3f3f;
int mp[MAXN][MAXN],dt[MAXN][MAXN];
int fa[MAXN][MAXN];
double res;
void Floyd(int n)
{
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)//一定是<k
            for(int j=1;j<k;j++)
            {
                if(mp[i][k]==INF||mp[k][j]==INF||dt[j][i]==INF) continue;
                int tmp=mp[i][k]+mp[k][j]+dt[j][i];//注意不要写成dt[i][j]
                int num=0,p=j;
                while(p!=i)//逆向寻找前驱结点直到找到最前面的i,i->…->j
                {
                    num++;
                    p=fa[i][p];//fa[i][j]保存的不是k,而是fa[k][j].
                }
                num+=2;
                double ts=(double)tmp/(double)num;
                res=min(res,ts);
            }
        //正常的Floyd
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                int tmp=dt[i][k]+dt[k][j];
                if(tmp<dt[i][j]){
                    dt[i][j]=tmp;
                    fa[i][j]=fa[k][j];
                }
            }
    }
}
int main(int argc, char const *argv[])
{
    int N,ti=0;
    cin>>N;
    while(++ti<=N){
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
        {   
            if(i==j) mp[i][j]=dt[i][j]=0;//如果可以两个点,值=0,否则INF
            else mp[i][j]=dt[i][j]=INF;
            fa[i][j]=i;
        }
        while(m--){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            if(mp[u][v]<w) w=mp[u][v];
            mp[u][v]=dt[u][v]=w;
        }
        res=1e14;
        Floyd(n);
        printf("Case #%d: ",ti );
        if(res==1e14) puts("No cycle found.");
        else printf("%.2f\n",res );
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值