[Usaco2007 Dec]奶牛的旅行

题意:作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天。旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇。 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了城市中所有L(2 <= L <= 1000)座标志性建筑物(建筑物按1..L顺次编号),以及连接这些建筑物的P(2 <= P <= 5000)条道路。按照计划,那天早上Farmer John会开车将奶牛们送到某个她们指定的建筑物旁边,等奶牛们完成她们的整个旅行并回到出发点后,将她们接回农场。由于大城市中总是寸土寸金,所有的道路都很窄,政府不得不把它们都设定为通行方向固定的单行道。 尽管参观那些标志性建筑物的确很有意思,但如果你认为奶牛们同样享受穿行于大城市的车流中的话,你就大错特错了。与参观景点相反,奶牛们把走路定义为无趣且令她们厌烦的活动。对于编号为i的标志性建筑物,奶牛们清楚地知道参观它能给自己带来的乐趣值F_i (1 <= F_i <= 1000)。相对于奶牛们在走路上花的时间,她们参观建筑物的耗时可以忽略不计。 奶牛们同样仔细地研究过城市中的道路。她们知道第i条道路两端的建筑物 L1_i和L2_i(道路方向为L1_i -> L2_i),以及她们从道路的一头走到另一头所需要的时间T_i(1 <= T_i <= 1000)。 为了最好地享受她们的休息日,奶牛们希望她们在一整天中平均每单位时间内获得的乐趣值最大。当然咯,奶牛们不会愿意把同一个建筑物参观两遍,也就是说,虽然她们可以两次经过同一个建筑物,但她们的乐趣值只会增加一次。顺便说一句,为了让奶牛们得到一些锻炼,Farmer John要求奶牛们参观至少2个建筑物。 请你写个程序,帮奶牛们计算一下她们能得到的最大平均乐趣值。

01规划类,推波式子后发现可以,二分答案,然后根据式子更新每边权值,spfa判负环,有的话答案就更大。

#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=1010,M=5010;
struct E{
    int u,v,t;
}edge[M];
int n,m,a[N];
int tot,hd[N],nxt[M*2],to[M*2],q[N*M*2],vis[N];
bool inq[N];db dis[N],cost[M*2];
void add(int u,int v,db w)
{nxt[++tot]=hd[u],to[tot]=v,cost[tot]=w,hd[u]=tot;}
bool spfa()
{
    int hed=0,tail=1,nw;
    memset(inq,0,sizeof inq);
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)
    {
        inq[i]=vis[i]=1;
        q[++hed]=i;
    }
    while(hed>=tail)
    {
        nw=q[tail++];
        for(int i=hd[nw];i!=-1;i=nxt[i])
        {
            if(dis[to[i]]>dis[nw]+cost[i])
            {
                dis[to[i]]=dis[nw]+cost[i];
                if(!inq[to[i]])
                {
                    q[++hed]=to[i];
                    ++vis[to[i]];
                    if(vis[to[i]]>n)return 1;
                }
                inq[to[i]]=1;
            }
        }
        inq[nw]=0;
    }
    return 0;
}
bool check(db x)
{
    memset(hd,-1,sizeof hd),tot=-1;
    for(int i=1;i<=m;i++)
        add(edge[i].u,edge[i].v,(db)x*edge[i].t-a[edge[i].v]);
    return spfa(); 
}
int main()
{
    int u,v,w;db l=0,r=0,mid,ans;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),r+=a[i];
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].t);
    for(;r-l>1e-4;)
    {
        mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid-1e-3;
    }
    printf("%.2lf",l);
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/82686286