POJ 3621 Sightseeing Cows(01分数规划+二分+Spfa判负环)

来源:互联网 发布:linux java开发 编辑:程序博客网 时间:2024/04/28 13:40

Description
给出一张有向图,求一个回路使其点权和/边权和最大(保证有回路)
Input
第一行为两个整数n和m表示点数和边数,之后n个整数表示n个点的点权,最后m行每行三个整数a,b,c表示a点到b点有一条权值为c的边
Output
输出一条回路的最大点权和/边权和值
Sample Input
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2
Sample Output
6.00
Solution
01分数规划,即求最大的ans=sum(val[i])/sum(cost[u][v]),方程可化为ans*sum(cost[u][v])-sum(val[i])=0,二分ans,每次将u->v的边权变为ans*cost[u][v]-val[u],判断图中是否存在负环,如果存在说明ans过小,不存在说明ans过大,判负环可以用spfa来判,即若一个点入队列数超过点数n说明存在负环
Code

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<queue>#include<cmath>using namespace std;#define INF 0x3f3f3f3f#define maxn 1111#define maxm 11111#define eps 1e-3struct edge{    int to,next;    double cost;}g[maxm];int head[maxm],tol,cnt[maxn];int n,m;double val[maxn],dis[maxn];void init(){    memset(head,-1,sizeof(head));    tol=0;}void add(int u,int v,double c){    g[tol].cost=c;    g[tol].to=v;    g[tol].next=head[u];    head[u]=tol++;}int spfa(double x){    bool vis[maxn];    memset(vis,false,sizeof(vis));    memset(cnt,0,sizeof(cnt));    queue<int>que;    while(!que.empty())que.pop();    for(int i=0;i<=n;i++)        dis[i]=INF;    cnt[1]++;    dis[1]=0;    vis[1]=true;    que.push(1);    while(!que.empty())    {        int u=que.front();        que.pop();        vis[u]=false;        for(int i=head[u];i!=-1;i=g[i].next)        {            int v=g[i].to;            double c=g[i].cost;            double w=x*c-val[u];            if(dis[v]>dis[u]+w)            {                dis[v]=dis[u]+w;                if(!vis[v])                {                    vis[v]=true;                    que.push(v);                    cnt[v]++;                    if(cnt[v]>=n)return 1;                }            }        }    }    return 0;}int main(){    while(~scanf("%d%d",&n,&m))    {        init();        for(int i=1;i<=n;i++)scanf("%lf",&val[i]);        for(int i=1;i<=m;i++)        {            int u,v;double c;            scanf("%d%d%lf",&u,&v,&c);            add(u,v,c);        }        double l=0,r=1111,mid;        while(fabs(r-l)>eps)        {            mid=(l+r)/2;            if(spfa(mid))l=mid;            else r=mid;        }        printf("%.2lf\n",mid);    }    return 0;}
0 0
原创粉丝点击