• Luogu P1251 餐巾计划问题 (最小费用最大流、拆点)


    P1251 餐巾计划问题

    题目大意:

    见题面

    思路:

    将一天拆点为晚上和白天。

    跑最小费用最大流。

    在此放两个模板。

    Code: 79ms / 3.23MB / 3.03KB C++17 O2
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL N = 8005;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    struct MCMF
    {
        struct EDGE
        {
            LL nxt, to, cost, flow;
        } ee[N*N];
        LL n, s, t;
        LL cur[N], head[N], vis[N], a[N];
        LL dis[N];
        LL mincost = 0, maxflow = 0;
        inline void AD(LL from, LL to, LL flow, LL cost)
        {
            ee[++cnt].nxt = head[from];
            ee[cnt].to = to;
            ee[cnt].cost = cost;
            ee[cnt].flow = flow;
            head[from] = cnt;
        }
        LL cnt = 1;
        inline void add_edge(LL u, LL v, LL flow, LL cost)
        {
            AD(u, v, flow, cost);
            AD(v, u, 0, -cost);
        }
        inline LL spfa()
        {
            for (LL i = 1; i <= n; ++i)
                dis[i] = INF;
            queue<LL> q;
            q.push(s);
            dis[s] = 0;
            vis[s] = 1;
            while (!q.empty())
            {
                LL u = q.front();
                vis[u] = 0;
                q.pop();
                for (LL i = head[u]; i; i = ee[i].nxt)
                {
                    LL v = ee[i].to;
                    if (!ee[i].flow)
                        continue;
                    if (ee[i].flow && dis[v] > dis[u] + ee[i].cost)
                    {
                        dis[v] = dis[u] + ee[i].cost;
                        if (!vis[v])
                        {
                            vis[v] = 1;
                            q.push(v);
                        }
                    }
                }
            }
            return dis[t] != INF;
        }
        inline LL dfs(LL u, LL flow)
        {
            if (u == t)
                return flow;
            LL rest = flow;
            vis[u] = 1;
            for (LL i = cur[u]; i && rest; i = ee[i].nxt)
            {
                cur[u] = i;
                LL v = ee[i].to;
                LL w = ee[i].cost, flow = ee[i].flow;
                if (ee[i].flow && (dis[v] == dis[u] + w) && !vis[v])
                {
                    LL k = dfs(v, min(flow, rest));
                    if (k)
                    {
                        maxflow += w;
                        mincost += k * w;
                        ee[i].flow -= k;
                        ee[i ^ 1].flow += k;
                        rest -= k;
                    }
                }
            }
            vis[u] = 0;
            return flow - rest;
        }
        void gkd()
        {
            while (spfa())
            {
                for (LL i = 1; i <= n; ++i)
                    cur[i] = head[i];
                dfs(s, INF);
            }
        }
        void init(LL nn, LL ss, LL tt)
        {
            n = nn, s = ss, t = tt;
            for (LL i = 0; i <= n; i++)
                head[i] = 0;
        }
    } mc;
    
    int main()
    {
    	LL n, m, s, t;
    	cin >> n;
    	s = 2 * n + 1; //源点不要0-index(从0开始
    	t = 2 * n + 2;
            mc.init(2 * n + 2, s, t);
    	for (LL i = 1; i <= n; i++) {
    		LL x; cin >> x;
    		mc.add_edge(s, i, x, 0);
    		mc.add_edge(i + n, t, x, 0);
    	}
    	LL p, t1, c1, t2, c2; cin >> p >> t1 >> c1 >> t2 >> c2;
    	for (LL i = 1; i <= n; i++) {
    		if (i + 1 <= n) mc.add_edge(i, i + 1, INF, 0);
    		if (i + t1 <= n) mc.add_edge(i, i + n + t1, INF, c1);
    		if (i + t2 <= n) mc.add_edge(i, i + n + t2, INF, c2);
    		mc.add_edge(s, i + n, INF, p);
    	}
            mc.gkd();
            cout << mc.mincost << endl;
    	return 0;
    }
    
    Code: 1.47s / 2.97MB / 2.05KB C++17 O2
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL N = 8010;
    struct node
    {
    	LL v, flow, cost, next;
    }edge[N*N];
    LL head[N], dis[N], vis[N], pre[N], rec[N], cnt;
    queue<LL> q;
    inline void init()
    {
    	cnt = 0;
    	memset(head, -1, sizeof(head));
    }
    inline void add_edge(LL u, LL v, LL f, LL c)
    {
    	edge[cnt].v = v; edge[cnt].flow = f; edge[cnt].cost = c;
    	edge[cnt].next = head[u]; head[u] = cnt++;
    	edge[cnt].v = u; edge[cnt].flow = 0; edge[cnt].cost = -c;
    	edge[cnt].next = head[v]; head[v] = cnt++;
    }
    LL SPFA(LL s, LL t)
    {
    	memset(dis, 0x3f, sizeof dis);
    	memset(vis, 0, sizeof vis);
    	while(!q.empty()) q.pop();
    	q.push(s); dis[s] = 0; vis[s] = 1;
    	while(!q.empty())
    	{
    		LL tp = q.front(); q.pop();
    		vis[tp] = 0;
    		LL k = head[tp];
    		while(k != -1)
    		{
    			if(dis[edge[k].v] > dis[tp] + edge[k].cost && edge[k].flow)
    			{
    				dis[edge[k].v] = dis[tp] + edge[k].cost;
    				pre[edge[k].v] = tp; rec[edge[k].v] = k;
    				if(vis[edge[k].v] == 0)
    				{
    					vis[edge[k].v] = 1;
    					q.push(edge[k].v);
    				}
    			}
    			k = edge[k].next;
    		}
    	}
    	if(dis[t] == INF) return 0;
    	return 1;
    }
    pair<LL, LL> Mcmf(LL s, LL t)
    {
    	LL minflow, k, mincost = 0, maxflow = 0;
    	while(SPFA(s, t))
    	{
    		k = t; minflow = INF;
    		while(k != s)
    		{
    			minflow = min(minflow, edge[rec[k]].flow);
    			k = pre[k];
    		}
    		k = t; maxflow += minflow;
    		while(k != s)
    		{
    			mincost += minflow*edge[rec[k]].cost;
    			edge[rec[k]].flow -= minflow;
    			edge[rec[k]^1].flow += minflow;
    			k = pre[k];
    		}
    	}
    	return make_pair(maxflow, mincost);
    }
    
    int main()
    {
    	init(); // do not forget it
    	LL n, m, s, t;
    	cin >> n;
    	s = 0;
    	t = 2 * n + 1;
    	for (LL i = 1; i <= n; i++) {
    		LL x; cin >> x;
    		add_edge(s, i, x, 0);
    		add_edge(i + n, t, x, 0);
    	}
    	LL p, t1, c1, t2, c2; cin >> p >> t1 >> c1 >> t2 >> c2;
    	for (LL i = 1; i <= n; i++) {
    		if (i + 1 <= n) add_edge(i, i + 1, INF, 0);
    		if (i + t1 <= n) add_edge(i, i + n + t1, INF, c1);
    		if (i + t2 <= n) add_edge(i, i + n + t2, INF, c2);
    		add_edge(s, i + n, INF, p);
    	}
    	pair<LL, LL> ans = Mcmf(s, t);
    	cout << ans.second << endl;
    	return 0;
    }
    
  • 相关阅读:
    宝塔相关问题
    免费xshell下载
    服务器断电mysql无法恢复
    mysql相关知识
    svn
    tortoisesvn下载 和svn 安装
    nginx+lua乐观锁实现秒杀
    c# asp.net 生成唯一订单号
    c# 关闭软件 进程 杀死进程
    国内开源软件镜像地址搜集
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/13953961.html
Copyright © 2020-2023  润新知