zoukankan      html  css  js  c++  java
  • 洛谷P3778 [APIO2017]商旅——01分数规划

    题目:https://www.luogu.org/problemnew/show/P3778

    转化有点技巧;

    其实直接关注比率的上下两项,也就是盈利和时间;

    通过暴枚和 floyd 可以处理出两两点间的最大盈利和最小时间,就不用再去关注原图了;

    然后就是裸的01分数规划,枚举 ans ,连完全图,判断正环,若有则答案可行;

    注意SPFA里一开始把每个点都入队;还要注意0环,代表此时正好是 ans;

    WA了十几遍只因为读入优化少写了一个等号...

    细节真令人心碎...50个点,错那么一个两个的...

    改成 int ,只把SPFA里的 dis 设成 long long ,就A了...为什么全 long long 就不行啊...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long ll;
    queue<int>q;
    int const maxn=105,maxk=1005,inf=0x3f3f3f3f;
    int map[maxn][maxn],val[maxn][maxn],l,r,ans,len[maxn],b[maxn][maxk],s[maxn][maxk];
    int n,m,K;
    ll dis[maxn];
    bool vis[maxn];
    int rd()
    {
        int ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }
    bool pd(int nw)
    {
        while(q.size())q.pop();
        for(int i=1;i<=n;i++)q.push(i),dis[i]=0,vis[i]=len[i]=1;//每个点入队 
        while(q.size())
        {
            int x=q.front(); q.pop(); vis[x]=0;
            for(int u=1;u<=n;u++)
                if(dis[u]<=dis[x]+(ll)val[x][u]-(ll)nw*map[x][u])//0环 
                {
                    dis[u]=dis[x]+(ll)val[x][u]-(ll)nw*map[x][u];
                    if(!vis[u])vis[u]=1,q.push(u),len[u]++;
    //                len[u]=len[x]+1;
    //                if(!vis[u])vis[u]=1,q.push(u);
                    if(len[u]>n)return 1;
                }
        }
        return 0;
    }
    int main()
    {
        n=rd(); m=rd(); K=rd();
        memset(map,0x3f,sizeof map);
    //    memset(val,-0x3f,sizeof val);
        for(int i=1;i<=n;i++)
        {
    //        map[i][i]=0;//
            for(int j=1;j<=K;j++){b[i][j]=rd(); s[i][j]=rd();}
        }
        for(int i=1,x,y,z;i<=m;i++)
        {
            x=rd(); y=rd(); z=rd();
            if(z<map[x][y])map[x][y]=z;
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)    
    //            if(map[i][k]!=inf&&map[k][j]!=inf)
                    map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)    
    //        if(map[i][j]!=inf)
            {
    //            val[i][j]=0;//至少是0 
                for(int k=1;k<=K;k++)    
                if(b[i][k]!=-1&&s[j][k]!=-1)
    //            if(b[i][k]>=0&&s[j][k]>=0)
                    val[i][j]=max(val[i][j],s[j][k]-b[i][k]),r=max(r,val[i][j]);
            }
                
        l=0;r=inf;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(pd(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    74.Maximal Rectangle(数组中的最大矩阵)
    73.Largest Rectangle in Histogram(最大矩形)
    72.Minimum Window Substring(最小子串窗口)
    71.Edit Distance(编辑距离)
    70.Trapping Rain Water(容水量)
    69.Daily Temperatures(日常气温)
    68.Palindromic Substrings(回文字符串的个数)
    67.Task Scheduler(任务规划)
    66.Subarray Sum Equals K(子数组和为K的个数)
    65.Longest Increasing Subsequence(最长增长子序列)
  • 原文地址:https://www.cnblogs.com/Zinn/p/9193991.html
Copyright © 2011-2022 走看看