Contest20140710 loop bellman-ford求负环&&0/1分数规划

loop|loop.in|loop.out


题目描述:

给出一个有向带权图,权为边权,求一个简单回路,使其平均边权最小。

简单回路指不多次经过同一个点的回路。


输入格式:

第一行两个整数,表示图的点数n和图的边数m

接下来m行,每行三个整数a,b,c表示一条从a指向b权为c的有向边。


输出格式:

一行一个实数,表示最小平均边权,保留两位小数。


样例输入:

4 5

1 2 3

2 3 5

3 1 4

3 4 3

4 1 2


样例输出:

3.25


数据范围:

30% n<=10 ,m<=20

100% n<=600,m<=1000,0<=c<=32768

保证原图强连通,无自环

 

hja的优化方法:类似题目可以将浮点数乘10000转换为整数,但是有爆int的风险。

求负环用bellman-ford O(NV)

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 660
#define MAXE 5000
#define PROB "loop"
#define eps 1e-4
#define INF 0x3f3f3f3f3f3f3f3fLL
#define inf 1E1000
#ifdef unix
#define LL "%lld"
#else
#define LL "%I64d"
#endif
typedef long long qword;
struct edge
{
        int x,y;
        qword z;
}el[MAXE];
qword dis[MAXN];
int main()
{
        freopen(PROB".in","r",stdin);
        //freopen(PROB".out","w",stdout);
        int n,m;
        scanf("%d%d",&n,&m);
        int i,j,k,x,y;
        qword z;
        qword l,r,mid;
        l=r=0;
        for (i=0;i<m;i++)
        {
                scanf("%d%d"LL,&x,&y,&z);
                x--;y--;
                z*=10000;
                el[i].x=x;
                el[i].y=y;
                el[i].z=z;
                if(z<0)l+=z;
                else r+=z;
        }
        bool flag;
        while (l+1<r)
        {
                mid=(l+r)/2;
                for (i=0;i<=n;i++)dis[i]=INF;
                dis[0]=0;
                flag=false;
                for (i=0;i<m;i++)
                {
                        el[i].z-=mid;
                }
                for (i=0;i<n;i++)
                {
                        for(j=0;j<m;j++)
                        {
                                if (dis[el[j].x]+el[j].z<dis[el[j].y])
                                        dis[el[j].y]=dis[el[j].x]+el[j].z;
                        }
                }
                for (i=0;i<n;i++)
                {
                        for(j=0;j<m;j++)
                        {
                                if (dis[el[j].x]+el[j].z<dis[el[j].y])
                                        flag=true;
                                if (flag)break;
                        }
                        if (flag)break;
                }
                for(i=0;i<m;i++)el[i].z+=mid;
                if (flag)
                {
                        r=mid;
                }else
                {
                        l=mid;
                }
        }
        printf("%.2lf
",(double)r/10000.0);
}

 

 

by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

本博客已停用,新博客地址:http://mhy12345.xyz

原文地址:https://www.cnblogs.com/mhy12345/p/3837300.html