2020牛客暑期多校训练营(第一场)H.Minimum-cost Flow

题目链接

题解思路:其实思路很简单,跑一遍费用流后记录每一条增广路的流量和花费,队这些增广路按照花费排序,之后对每次询问只需要去枚举这些增广路即可,把每条(1,x/y)的边看作是(y,x)的边,最后再对答案除y,这样就有效避免了分数出现的尴尬情况。


 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
#define endl '\n'
#define p4 puts("444")
const int N = 50+10,M = 1e2+10;
const double EPS = 1e-12;
const ll mod = 1e9+7;

int n,m,s,t,q,cnt,maxflow,tot;
int head[N],cur[N],inq[N],pre[N],path[N];
ll dis[N],cost;

struct edge{
    int to,next,cap;
    ll cost;
}E[M<<1];
struct node{
    void Add(int u,int v,int w,ll c){
        E[cnt].to=v;
        E[cnt].cap=w;
        E[cnt].next=head[u];
        E[cnt].cost=c;
        head[u]=cnt++;
    }
    bool Spfa(){
        for(int i=1;i<=n;i++)cur[i]=head[i],dis[i]=1e18,inq[i]=0,pre[i]=0;
        queue<int>que;
        que.push(s);
        inq[s]=1;
        dis[s]=0;
        while(!que.empty()){
            int u=que.front();que.pop();
            inq[u]=0;
            for(int i=head[u];~i;i=E[i].next){
                int v=E[i].to;
                if(E[i].cap&&dis[v]>dis[u]+E[i].cost){
                    pre[v]=i;
                    dis[v]=dis[u]+E[i].cost;
                    if(!inq[v]){
                        inq[v]=1;
                        que.push(v);
                    }
                }
            }
        }
        return dis[t]==1e18 ? 0 : 1;
    }
    void Solve(){
        while(Spfa()){
            int flow=1e9;
            for(int i=t;i!=s;i=E[pre[i]^1].to)flow=min(flow,E[pre[i]].cap);
            maxflow+=flow;
            path[++tot]=0;
            for(int i=t;i!=s;i=E[pre[i]^1].to){
                E[pre[i]].cap-=flow;
                E[pre[i]^1].cap+=flow;
                cost+=flow*E[pre[i]].cost;
                path[tot]+=E[pre[i]].cost;
            }
        }
    }
    void Init(){
        maxflow=cost=cnt=tot=0;
        memset(head,-1,sizeof(head));
    }
}EK;

int main()
{
    while(~scanf("%d %d",&n,&m)){
        EK.Init();
        int a,b; ll c;
        for(int i=1;i<=m;i++){
            scanf("%d %d %lld",&a,&b,&c);
            EK.Add(a,b,1,c);
            EK.Add(b,a,0,-c);
        }
        ll x,y;
        s=1,t=n;
        EK.Solve();
        scanf("%d",&q);
        while(q--){
            int flag=0;
            ll nowflow=0,nowcost=0;
            scanf("%lld %lld",&x,&y);
            for(int i=1;i<=tot;i++){
                if(x*(tot-i+1)<y-nowflow){
                    flag=1;
                    break;
                }
                int need=min(x,y-nowflow);
                nowflow+=need;
                nowcost+=path[i]*need;
            }
            if(flag)puts("NaN");
            else cout<<nowcost/__gcd(nowcost,y)<<"/"<<y/__gcd(nowcost,y)<<endl;
        }
    }
}

 

posted @ 2020-07-13 15:28  Mmasker  阅读(223)  评论(0编辑  收藏  举报