zoukankan      html  css  js  c++  java
  • 【luogu P3410 拍照】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3410
    这个题就是求一个最大权闭合图

    在一个图中,一些点构成一个集合,且集合中的出边指向的终点也在这个集合中,则我们称这个集合为闭合图。

    整个图中点的权值之和最大的闭合图,为最大权闭合图。

    最大权闭合图可以用网络流来求

    造出一个超级源点S和一个超级汇点T,把S连边到所有带有正权的点上,容量是这个点的权;把所有带负权的点连边到T,容量是这个点的权的相反数。原来的边呢,把它们的容量都设成无限大。

    (带负权的是员工需要花费的,正权是我们的收入,收入-花费为所求)

    之后我们跑一遍最大流。

    答案就是图中的所有正权值之和减去最小割容量。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e6 + 10;
    const int inf = 1e9;
    int n, m, s, t, deep[maxn], maxflow, w[maxn], ans;
    struct edge{
    	int next, to, flow;
    }e[maxn<<2];
    int head[maxn], cnt = -1;
    queue<int> q;
    void add(int u, int v, int w)
    {
    	e[++cnt].flow = w; e[cnt].next = head[u]; e[cnt].to = v; head[u] = cnt;
    	e[++cnt].flow = 0; e[cnt].next = head[v]; e[cnt].to = u; head[v] = cnt;
    }
    bool bfs(int s, int t)
    {
    	memset(deep, 0x7f, sizeof(deep));
    	while(!q.empty()) q.pop();
    	q.push(s); deep[s] = 0;
    	while(!q.empty())
    	{
    		int now = q.front(); q.pop();
    		for(int i = head[now]; i != -1; i = e[i].next)
    		{
    			if(deep[e[i].to] > inf && e[i].flow)
    			{
    				deep[e[i].to] = deep[now] + 1;
    				q.push(e[i].to);
    			}
    		}
    	}
    	if(deep[t] < inf) return true;
    	else return false;
    }
    int dfs(int now, int t, int limit)
    {
    	if(!limit || now == t) return limit;
    	int flow = 0, f;
    	for(int i = head[now]; i != -1; i = e[i].next)
    	{
    		if(deep[e[i].to] == deep[now] + 1 && (f = dfs(e[i].to, t, min(e[i].flow, limit))))
    		{
    			flow += f;
    			limit -= f;
    			e[i].flow -= f;
    			e[i^1].flow += f;
    			if(!limit) break;
    		}
    	}
    	return flow;
    }
    void Dinic(int s, int t)
    {
    	while(bfs(s, t))
    	maxflow += dfs(s, t, inf);
    }
    int main()
    {
    	memset(head, -1, sizeof(head));
    	scanf("%d%d",&m,&n);
    	s = 1, t = 2 + n + m;
    	for(int i = 1; i <= m; i++)
    	{
    		int u;
    		scanf("%d",&w[i]);
    		ans += w[i];
    		while(scanf("%d",&u) && u != 0)
    		{
    			add(i + n + 1, u + 1, inf);
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		int c;
    		scanf("%d",&c);
    		add(i + 1, t, c);
    	}
    	for(int i = 1; i <= m; i++)
    	{
    		add(s, i + n + 1, w[i]);
    	}
    	Dinic(s, t);
    	printf("%d",ans - maxflow);
    	return 0;
    }
    
  • 相关阅读:
    torch上疑问用法总结
    matplotlib库介绍
    java学习总结
    java高级并发编程实战
    java的spi思想--打破双亲委派模型的操作
    linux设置静态ip步骤流程
    jvm调优参数设置
    jvisualvm插件的基本使用
    jvm常见的gc种类
    jvm调优案例与步骤
  • 原文地址:https://www.cnblogs.com/MisakaAzusa/p/9445826.html
Copyright © 2011-2022 走看看