POJ 3621 最优比率环

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#define inf 0x3f3f3f
#define maxn 3000
#define maxm 10000
#define eps 1e-3
using namespace std;

//spfa判负权回路+最优比率环。
// 大于n-1退出
//假设有一个点,除了自身,所有点都可以更新它……
//入队次数超过结点数量,证明存在回路
比率环只算终点value的思想!!!
过了,但建边的神奇性还要再想一下。。。

int em;
int n;
int head[maxn];

struct node
{
    int u,v,next;double w;
}edge[maxm];

void addedge(int u,int v,double w)
{
    edge[em].u=u;
    edge[em].v=v;
    edge[em].w=w;
    edge[em].next=head[u];
    head[u]=em++;
}


double d[maxn];
bool vis[maxn];
int cnt[maxn];


double a[maxn];

bool spfa(int s,double ans)///是可以随意选定起点的么??
{
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)
        d[i]=inf;
   d[s]=0;
   vis[s]=1;
   queue<int> q;
   q.push(s);
   cnt[s]++;//首先注意这里的加一
   while(!q.empty())
   {
       int x=q.front();
       q.pop();

       vis[x]=false;
       for(int i=head[x];~i;i=edge[i].next)
       {
           int v=edge[i].v;
           double val=edge[i].w*ans-a[x];
           if(d[v]>d[x]+val)
           {
            d[v]=d[x]+val;
            if(!vis[v])
            {
                cnt[v]++;在这里判断负环,到底是大于等于N,还是大于n?
              if(cnt[v]>=n) return true;
                vis[v]=true;
                q.push(v);
            }
           }
       }
   }
    return false;
}



void solve()
{
    double l=0;double r=1000.0;///会不会太大了???
    while(r-l>eps)
    {
        double mid=(l+r)*0.5;
        memset(cnt,0,sizeof(cnt));
        if(spfa(1,mid))
            l=mid;
        else
            r=mid;;
       // printf("%.5lf %.5lf\n",mid,build(mid));
    }
    printf("%.2lf\n",l);
}


int  x,y;
double z;


int main()
{
    int m;
//    freopen("input.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        em=0;memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
            scanf("%lf",&a[i]);
        for(int i=1;i<=m;i++)
            scanf("%d%d%lf",&x,&y,&z),addedge(x,y,z);///为什么要建有向边???????????????????????????????????????
        solve();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值