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;
    }
    
  • 相关阅读:
    性能优化方法
    JSM的topic和queue的区别
    关于分布式事务、两阶段提交协议、三阶提交协议
    大型网站系统与Java中间件实践读书笔记
    Kafka设计解析:Kafka High Availability
    kafka安装和部署
    String和intern()浅析
    JAVA中native方法调用
    Java的native方法
    happens-before俗解
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/10386807.html
Copyright © 2011-2022 走看看