• Luogu P1646 【[国家集训队]happiness】


    Description

    传送门


    Solution

    一种列方程的套路。

    我们先单独找出两个点的关系来考虑。

    假设有(x)(y)两个同学,向(S)连边代表选理科,向(T)连边代表选文科。设(S)(x)连的有向边为(a)(S)(y)连的有向边为(b)(x)(T)连的有向边为(c)(y)(T)连的有向边为(d)(x)(y)之间连了一条双向边(e),割掉一条边的流量代表损失了这么多的愉悦值。

    设都选理科的愉悦值是(v_1),都选文科的愉悦值是(v_2),按照题意可列方程组如下:

    [a + b = v_1 ]

    这是对应的两个同学都选理科。

    [c + d = v_2 ]

    这是对应的两个同学都选文科。

    [a + e + d = v_1 + v_2 ]

    这是对应的(x)选理科,(y)选文科。

    [b + e + c = v_1 + v_2 ]

    这是对应的(x)选文科,(y)选理科。

    解得

    [a = b = frac{v_1}{2}, c = d = frac{v_2}{2}, e = frac{v_1 + v_2}{2} ]

    那么我们只需要从(S)向每个点连一条容量为该同学选理科的愉悦值和他所有相邻的同学选理科的之和的有向边,从每个同学向(T)连一条容量为该同学选文科和他所有相邻的同学都选文科的愉悦值之和的有向边。

    每个同学向它相邻的同学连一条容量为他们同时都选理科或者文科的愉悦值的平均值的双向边。

    那么答案就是所有愉悦值的和减去最小割。

    注意因为要算平均值,所以可能出现小数,这样在一开始连边的时候乘二,最后再除以二就行了。


    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue> 
    using namespace std;
    
    const int N = 1000050;
    const int M = 2000050;
    const int INF = 999999999;
    
    int head[N], num = 1, n, m, s, t, tu[500][500][2], tmp[500][500], sum, d[N], x;
    
    struct Node
    {
    	int next, to, flow;
    } edge[M * 2];
    
    void Addedge(int u, int v, int w)
    {
    	edge[++num] = (Node){head[u], v, w};
    	head[u] = num;
    	return;
    }
    
    void Add(int u, int v, int w)
    {
    	Addedge(u, v, w);
    	Addedge(v, u, 0);
    	return;
    }
    
    int Id(int a, int b)
    {
    	return (a - 1) * m + b;
    } 
    
    template <class T>
    void Read(T &x)
    {
    	x = 0; int p = 0; char st = getchar();
    	while (st < '0' || st > '9') p = (st == '-'), st = getchar();
    	while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) +st - '0', st = getchar();	
    	x = p ? -x : x;
    	return;
    } 
    
    template <class T>
    void Put(T x)
    {
    	if (x < 0) putchar('-'), x = -x;
    	if (x > 9) Put(x / 10);
    	putchar(x % 10 + '0');
    	return; 
    }
    
    bool Bfs()
    {
        queue<int> q;
        for (int i = 0; i <= t; i++) d[i] = 0;
        d[s] = 1; q.push(s);
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            for (int i = head[u]; i; i = edge[i].next)
                if (!d[edge[i].to] && edge[i].flow)
                {
                    d[edge[i].to] = d[u] + 1;
                    q.push(edge[i].to);
                    if (edge[i].to == t) return 1;
                }
        }
        return 0;
    }
    
    int Dinic(int x, int flow)
    {
        if (x == t || !flow) return flow;
        int rest = flow;
        for (int i = head[x]; i && rest; i = edge[i].next)
            if (edge[i].flow && d[edge[i].to] == d[x] + 1)
            {
                int v = edge[i].to;
                int tmp = Dinic(v, min(rest, edge[i].flow));
                rest -= tmp;
                edge[i].flow -= tmp;
                edge[i ^ 1].flow += tmp;
                if (!tmp) d[v] = 0;
            }
        return flow - rest;
    }
    
    int Maxflow()
    {
    	int maxflow = 0, tmp;
    	while (Bfs())
    	{
    		tmp = Dinic(s, INF);
    		if (tmp) maxflow += tmp;
    	}
    	return maxflow;
    }
    
    int main()
    {
    	Read(n); Read(m); t = n * m + 1;
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			Read(x);
    			sum += x;
    			tu[i][j][1] += x * 2;
    		}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			Read(x);
    			sum += x;
    			tu[i][j][0] += x * 2;
    		}
    	for (int i = 1; i <= n - 1; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			Read(x);
    			sum += x;
    			tmp[i][j] += x;
    			tu[i][j][1] += x;
    			tu[i + 1][j][1] += x;
    		}
    	for (int i = 1; i <= n - 1; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			Read(x);
    			sum += x;
    			tmp[i][j] += x;
    			Add(Id(i, j), Id(i + 1, j), tmp[i][j]);
    			Add(Id(i + 1, j), Id(i, j), tmp[i][j]);
    			tu[i][j][0] += x;
    			tu[i + 1][j][0] += x;
    			tmp[i][j] = 0;
    		}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m - 1; j++)
    		{
    			Read(x);
    			sum += x;
    			tmp[i][j] += x;
    			tu[i][j][1] += x;
    			tu[i][j + 1][1] += x; 
    		}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m - 1; j++)
    		{
    			Read(x);
    			sum += x;
    			tmp[i][j] += x;
    			Add(Id(i, j), Id(i, j + 1), tmp[i][j]);
    			Add(Id(i, j + 1), Id(i, j), tmp[i][j]);
    			tu[i][j][0] += x;
    			tu[i][j + 1][0] += x;
    		}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			Add(s, Id(i, j), tu[i][j][0]);
    			Add(Id(i, j), t, tu[i][j][1]);
    		}
    	Put(sum - Maxflow() / 2); 
    	return 0;
    }
    
  • 相关阅读:
    笔记:Struts2 的 JSON 插件
    笔记:Struts2 拦截器
    笔记:Struts2 文件上传和下载
    笔记:Struts2 文件上传和下载
    【学习总结】推荐系统-协同过滤原理
    【刷题】牛客网看到的鹅厂ML面筋-部分问题RecSys相关
    【刷题】【LeetCode】000-十大经典排序算法
    【刷题】【LeetCode】总
    【问题解决方案】pygame生成的窗口点右上角关闭按钮未响应问题的解决
    【刷题】若串 =’software’ ,其子串数目为:37
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13098060.html
Copyright © 2020-2023  润新知