zoukankan      html  css  js  c++  java
  • NOI2008 志愿者招募

    题目传送门

    Description

    一个项目分(n)天完成,每天需要(a_i)个志愿者。志愿者有(m)种招募方式,第(i)种从第(s_i)天工作到第(t_i)天,工资(c_i)元。求完成项目的最少花费。((nleq 10^3,mleq 10^4))

    Solution

    数据范围和题目描述都指向网络流,且是最小费用最大流。

    但如何建图?这就不显然了。

    以每天为一个节点,并建立源点和汇点。

    源点连第一天,最后一天连汇点,容量为(inf),费用为(0)

    每一天连后一天,容量为(inf-a_i),费用为(0)

    对于每一类志愿者,(s_i)(t_i),容量为(inf),费用为(c_i)

    然后跑最小费用最大流即可。

    为什么这样建图可行?不难发现,只要题目有解,最大流一定为(inf),也就是用有费用的流将所有的(a_i)都填满了。

    Code

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define int long long
    #define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
    #define per(i, a, b) for (register int i=(a); i>=(b); --i)
    using namespace std;
    const int N=10005, M=200005, inf=1ll<<60;
    struct node{int to, nxt, flow, cost;}edge[M];
    int head[N], vis[N], last[N], pre[N], flow[N], cost[N];
    int a[N], s[M], t[M], c[M], n, m, cnt, S, T;
    void prep(){memset(head, -1, sizeof(head)); cnt=-1;}
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
        return x*f;
    }
    
    void add(int u, int v, int f, int w)
    {
        edge[++cnt]=(node){v, head[u], f, w}; head[u]=cnt;
        edge[++cnt]=(node){u, head[v], 0, -w}; head[v]=cnt;
    }
    
    bool spfa()
    {
        rep(i, 1, n+3) cost[i]=inf; cost[S]=0;
        memset(vis, 0, sizeof(vis)); vis[S]=1;
        rep(i, 1, n+3) flow[i]=inf;
        queue<int> q; q.push(S); pre[T]=-1;
        while (!q.empty())
        {
            int u=q.front(); q.pop();
            for (int i=head[u]; ~i; i=edge[i].nxt)
            {
                vis[u]=0;
                int v=edge[i].to, w=edge[i].cost, f=edge[i].flow;
                if (f>0 && cost[u]+w<cost[v]) 
                {
                    pre[v]=u; last[v]=i; cost[v]=cost[u]+w;
                    flow[v]=min(flow[u], f);
                    if (!vis[v]) vis[v]=1; q.push(v);
                }
            }
        }
        return ~pre[T];
    }
    
    int EK()
    {
        int maxflow=0, mincost=0;
        while (spfa())
        {
            maxflow+=flow[T]; mincost+=flow[T]*cost[T];
            int u=T;
            while (u^S)
            {
                edge[last[u]].flow-=flow[T];
                edge[last[u]^1].flow+=flow[T];
                u=pre[u];
            }
        }
        return mincost;
    }
    
    signed main()
    {
        prep(); n=read(); m=read(); S=n+2; T=n+3;
        rep(i, 1, n) a[i]=read();
        rep(i, 1, m) s[i]=read(), t[i]=read(), c[i]=read();
        add(S, 1, inf, 0); add(n+1, T, inf, 0);
        rep(i, 1, n) add(i, i+1, inf-a[i], 0);
        rep(i, 1, m) add(s[i], t[i]+1, inf, c[i]);
        printf("%lld
    ", EK());
        return 0;
    }
    
    
  • 相关阅读:
    LeetCode 1245. Tree Diameter
    LeetCode 1152. Analyze User Website Visit Pattern
    LeetCode 1223. Dice Roll Simulation
    LeetCode 912. Sort an Array
    LeetCode 993. Cousins in Binary Tree
    LeetCode 1047. Remove All Adjacent Duplicates In String
    LeetCode 390. Elimination Game
    LeetCode 1209. Remove All Adjacent Duplicates in String II
    LeetCode 797. All Paths From Source to Target
    LeetCode 1029. Two City Scheduling
  • 原文地址:https://www.cnblogs.com/ACMSN/p/10749941.html
Copyright © 2011-2022 走看看