zoukankan      html  css  js  c++  java
  • CF_863_F(Netflow)

    codeforces_863_F

    题目大意:给出一个数组的大小(n<=50),以及每个位置填数的范围限制(若无限制,即为1-n),最后求填出数组的最小花费,定义总花费为数组中每个数出现次数的平方和。(sum_cnt[i]^2 (1<=i<=n))。
    题解:费用流,要不是最近在学,我都不敢信网络流这么强大,想清楚怎么转化和建边之后,实现没有什么细节,关键是转化,如果第一次遇见是挺吃脑子的。下面来给出建边:将每个数和Sn条边(容量1,花费为2*j-1j为这是这个数的第几条边),然后每个数和可以放这个数的位置连边(容量1, 费用0),最后每个位置和T连边(容量费用同上)。下面来解释一下建边的原因,因为题目要求的花费是出现次数的平方,那我们考虑其中一个数,怎么让花费是次数平方呢?最直接的想法就是连n条边(容量i,费用i, 1<=i<=n), 这样i*i(费用流的所谓的费用是单位费用,即单位流量的费用),表示i这个数用i次的费用,是不是很完美?可是,我们想想费用流是怎么跑的,它有个最短路,跑的是花费,那么问题来了,假设我们要当前这个数使用两次,那么讲道理应该跑e(2,2),这条边,可是其实两次是怎么跑的?是先跑了e(1,1),走一个流量,再从e(2,2)走一个流量,这样一来,花费是1+2=3 != 4,显然就错误了,那么问题来了,发现走几次其实就是用了几条这个数的边,那么有没有一个前缀和能让前i条边的边权和为i^2?答案就是1,3,5,7......这个等差数列的第i次前缀和就是i^2。那么最关键的建边解释完了,剩下的建边没什么好说的,容量1是因为每个位置最后只有一个数,而每个位置对于整个数列只贡献一个位置,花费0是因为,从S到所有数的连边泡完就算完了花费,后面自然为0

    PS:不要说什么LLF,SLFSPFA,就是势叠加的Dij直接莽(Dij记得加vis,奇快无比,因为T过,所以懂得,那次T得太惨了)。是真的难受,没看题解不知道怎么建边,大概猜到了会是网络流,因为画了画感觉可以用图做(都是美食节那题迫害的,至今未动)。

    时限:46ms / 3S

    #pragma comment(linkerr, "/STACK: 1024000000,1024000000")
    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define eb emplace_back
    #define em emplace
    #define pii pair<int,int>
    #define de(x) cout << #x << " = " << x << endl
    #define clr(a,b) memset(a,b,sizeof(a))
    #define INF (0x3f3f3f3f)
    #define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
    #define F first
    #define S second
    using namespace std;
    
    const int M = 2e5 + 15;
    const int N = 55;
    int mxflw = 0, mncst = 0;
    pii ans;
    int S, T;
    int n, q;
    pii a[N];
    struct Edge
    {
    	int v, f, w, nxt;
    };
    Edge e[M<<1];
    int h[N*4], ect;
    int g[N*4], dis[N*4];
    int pv[N*4], pe[M<<1];
    bool vis[N*4];
    void init()
    {
    	clr(h,-1);
    	ect = 0;
    }
    void _add( int u, int v, int f, int w )
    {
    	e[ect].v = v, e[ect].f = f, e[ect].w = w, e[ect].nxt = h[u], h[u] = ect++;
    	e[ect].v = u, e[ect].f = 0, e[ect].w =-w, e[ect].nxt = h[v], h[v] = ect++;
    }
    
    pii mfmc( int s, int t )
    {
    	while ( 1 )
    	{
    		priority_queue<pii> q;
    		clr(vis,false);
    		for ( int i = s; i <= t; i ++ )
    			dis[i] = INF; dis[s] = 0;
    		q.push( {0,s} );
    		while ( !q.empty() )
    		{
    			pii nw = q.top(); q.pop();
    			int u = nw.S;
    			if ( vis[u] ) continue;
    			vis[u] = true;
    			for ( int i = h[u]; i+1; i = e[i].nxt )
    			{
    				int v = e[i].v;
    				int cst = e[i].w + g[u] - g[v];
    				if ( e[i].f > 0 && dis[v] > dis[u] + cst )
    				{
    					dis[v] = dis[u] + cst;
    					pe[v] = i, pv[v] = u;
    					q.push( { -dis[v], v } );
    				}
    			}
    		}
    		if ( dis[t] == INF ) break;
    		for ( int i = s; i <= t; i ++ )
    			g[i] += dis[i];
    		int d = INF;
    		for ( int i = t; i != s; i = pv[i] )
    			d = min( d, e[ pe[i] ].f );
    		for ( int i = t; i != s; i = pv[i] )
    		{
    			int id = pe[i];
    			e[id].f -= d, e[id^1].f += d;
    		}
    		mxflw += d, mncst += d*g[t];
    	}
    	return { mxflw, mncst };
    }
    
    int main()
    {
    	init();
    	scanf("%d%d", &n, &q);
    	for ( int i = 1; i <= n; i ++ )
    		a[i].F = 1, a[i].S = n;
    	while ( q -- )
    	{
    		int p, l, r, v;
    		scanf("%d%d%d%d", &p, &l, &r, &v);
    		for ( int i = l; i <= r; i ++ )
    			if ( p == 1 ) a[i].F = max( a[i].F, v );
    			else a[i].S = min( a[i].S, v );
    	}
    	
    	S = 0, T = 2*n + 1;
    	for ( int i = 1; i <= n; i ++ )
    	{
    		for ( int j = 1; j <= n; j ++ )
    			_add( S, i, 1, 2*j-1 );		//S  ->  num
    		_add( i+n, T, 1, 0 );			//pos  ->  T
    	}
    	for ( int i = 1; i <= n; i ++ )
    	{
    		for ( int j = a[i].F; j <= a[i].S; j ++ )
    			_add( j, i+n, 1, 0 );		//num  ->  pos
    	}
    	ans = mfmc( S, T );
    	printf("%d
    ", ans.F == n ? ans.S : -1);
    	return 0;
    }
    
  • 相关阅读:
    状态压缩 + 暴力 HDOJ 4770 Lights Against Dudely
    简单几何(推公式) UVA 11646 Athletics Track
    简单几何(四边形形状) UVA 11800 Determine the Shape
    简单几何(求交点) UVA 11437 Triangle Fun
    计算几何模板
    简单几何(相对运动距离最值) UVA 11796 Dog Distance
    简单几何(求划分区域) LA 3263 That Nice Euler Circuit
    覆盖的面积 HDU
    Desert King 最小比率生成树 (好题)
    约会安排 (区间合并)毒瘤题
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/10386807.html
Copyright © 2011-2022 走看看