2020牛客多校训练第一场(待更新)

H.Minimum-cost Flow

分析:

可以先假设每条边的容量是1,然后跑mcmf,按费用从小到大求出各条增广路。然后对于q次询问,我们可以转化为每条边的容量为u,总流量(从原点出发的流)是v,求出此时的mincost,然后除以v即可

代码:

#include 
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 5e3 + 10;
const ll inf = 1e18;
struct edge
{
    ll v, cap, cost, nex;
    edge(ll v = 0, ll cap = 0, ll cost = 0, ll nex = 0) : v(v), cap(cap), cost(cost), nex(nex){}
}e[maxn];
int head[maxn];
ll dis[maxn], vis[maxn];
int pre[maxn], last[maxn];//记录某个点的上一条边
int n, m;
int s, t;
int tot;
ll sum[maxn];
int cnt = 0;

ll gcd(ll a, ll b)
{
    return !b ? a : gcd(b, a % b);
}

void init()
{
    mem(head, -1), tot = 0;
}

void addedge(int u, int v, int cap, int cost)
{
    e[tot] = edge(v, cap, cost, head[u]);
    head[u] = tot++;
}

int maxflow, mincost;

bool spfa()
{
    
    for(int i = 1; i <= n; i++) vis[i] = 0, dis[i] = inf;
    queue<int> q;
    dis[s] = 0, q.push(s), vis[s] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = e[i].nex)
        {
            int v = e[i].v;
            if(e[i].cap > 0 && dis[v] > dis[u] + e[i].cost)
            {
                dis[v] = dis[u] + e[i].cost;
                pre[v] = u;
                last[v] = i;
                if(!vis[v])
                    vis[v] = 1, q.push(v);
            }
        }
    }
    return dis[t] != inf;
}

void mcmf()
{
    maxflow = mincost = 0;
    cnt = 0;
    while(spfa())
    {
        ll nowflow = inf;
        int x = t;
        while(x != s)
            nowflow = min(nowflow, e[last[x]].cap), x = pre[x];
        maxflow += nowflow, mincost += nowflow * dis[t], sum[++cnt] = dis[t], sum[cnt] += sum[cnt - 1];
        x = t;
        while(x != s)
            e[last[x]].cap -= nowflow, e[last[x] ^ 1].cap += nowflow, x = pre[x];
    }
}

int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        init();
        for(int i = 1; i <= m; i++)
        {
            ll a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
            addedge(a, b, 1, c), addedge(b, a, 0, -c);
        }
        s = 1, t = n;
        mcmf();
        int q; scanf("%d", &q);
        while(q--)
        {
            ll u, v; scanf("%lld%lld", &u, &v);
            if(u * cnt < v) printf("NaN\n");
            else
            {
                ll num = v / u;
                ll res = u * sum[num];
                res += (sum[num + 1] - sum[num]) * (v - num * u);
                ll gcdd = gcd(res, v);
                printf("%lld/%lld\n", res / gcdd, v / gcdd);
            }
        }
    }
}

你可能感兴趣的:(牛客多校)