• [20220210联考] 一般图带权多重匹配


    前言

    成功向着成功相反的方向一直走可能也算一种成功吧qwq。

    题目

    链接就算了。

    \(n\) 个自然数 \(a_i\),以及 \(c_{i,j}\) 表示将 \(a_i\)\(a_j\) 都减一的代价,注意 \(i,j\) 可以相等,此时相当于一个数减两次。

    询问把所有数减到 \(0\) 的最小花费。无解输出 \(-1\)。数据范围中的 \(k\) 表示 \(a_i\) 为奇数的个数。

    \(1\le n\le 50;k\le 8;c_{i,j}=c_{j,i}\le 100000;a_{i}\le 100.\)

    讲解

    这么小的数据,这么小的代价,这长得也太网络流了吧!

    由于我见题不多,所以我就开始思考怎么让一个代价有两个固定点的流量。

    我想的是新建虚点,到虚点的边控制花费,然后虚点连出去的边控制流量,但是我并不会均分出去的流量,遂自闭。

    然而正解完全相反,两个点之间的边来控制花费,而点与源汇点的边控制流量!

    具体来说,我们将一次 \(c_{i,j}\) 的操作看作从 \(i\) 连向 \(j\) 的一条边,然后将 \(a_i\) 均分为入度和出度,至于奇数点只需暴力枚举入度多 \(1\) 还是出度多 \(1\),也就 \(C_{k}^{k/2}\) 至多 \(C_{8}^{4}\) 种情况。整个过程还可以看成欧拉路。

    正确性显然。

    时间复杂度不会算,总之就是情况数量乘上费用流的时间。

    代码

    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 105;
    const int INF = 0x3f3f3f3f;
    int n,k,S,T,ans = INF;
    int a[MAXN],c[MAXN][MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int head[MAXN],tot = 1;
    struct edge
    {
    	int v,w,c,nxt;
    }e[MAXN*MAXN<<2];
    void Add_Edge(int u,int v,int w,int c)
    {
    	e[++tot] = edge{v,w,c,head[u]};
    	head[u] = tot;
    }
    void Add_Double_Edge(int u,int v,int w,int c)
    {
    	Add_Edge(u,v,w,c);
    	Add_Edge(v,u,0,-c);
    }
    bool tag[MAXN],inq[MAXN];
    vector<int> odd;
    int pre[MAXN][2],flow[MAXN],dis[MAXN];
    bool bfs()
    {
    	for(int i = 1;i <= T;++ i) dis[i] = INF,flow[i] = 0;
    	dis[S] = 0; flow[S] = INF;
    	queue<int> q; q.push(S);
    	while(!q.empty())
    	{
    		int x = q.front(); q.pop(); inq[x] = 0;
    		for(int i = head[x],v; i ;i = e[i].nxt)
    			if(e[i].w > 0 && dis[x] + e[i].c < dis[v = e[i].v])
    			{
    				dis[v] = dis[x] + e[i].c;
    				flow[v] = Min(flow[x],e[i].w);
    				pre[v][0] = x;
    				pre[v][1] = i;
    				if(!inq[v]) inq[v] = 1,q.push(v);
    			}
    	}
    	return dis[T] < INF;
    }
    int MCMF()
    {
    	int ret = 0;
    	while(bfs())
    	{
    		ret += flow[T] * dis[T];
    		for(int now = T;now ^ S;now = pre[now][0])
    		{
    			e[pre[now][1]].w -= flow[T];
    			e[pre[now][1]^1].w += flow[T];
    		}
    	}
    	return ret;
    }
    void solve()
    {
    	tot = 1;
    	for(int i = 1;i <= T;++ i) head[i] = 0;
    	for(int i = 1;i <= n;++ i) 
    		if(a[i] & 1)
    		{
    			if(tag[i]) Add_Double_Edge(S,i,(a[i]>>1)+1,0),Add_Double_Edge(i+n,T,a[i]>>1,0);
    			else Add_Double_Edge(S,i,a[i]>>1,0),Add_Double_Edge(i+n,T,(a[i]>>1)+1,0);
    		}
    		else Add_Double_Edge(S,i,a[i]>>1,0),Add_Double_Edge(i+n,T,a[i]>>1,0);
    	for(int i = 1;i <= n;++ i)
    		for(int j = 1;j <= n;++ j)
    			Add_Double_Edge(i,j+n,INF,c[i][j]);
    	ans = Min(ans,MCMF());
    }
    void dfs(int x,int les)
    {
    	if(x == k)
    	{
    		solve();
    		return;
    	}
    	if(k-x-1 >= les) tag[odd[x]] = 0,dfs(x+1,les);
    	if(les) tag[odd[x]] = 1,dfs(x+1,les-1);
    }
    
    int main()
    {
    //	freopen("match.in","r",stdin);
    //	freopen("match.out","w",stdout);
    	n = Read();
    	for(int i = 1;i <= n;++ i) 
    		if((a[i] = Read()) & 1)
    			odd.emplace_back(i);
    	for(int i = 1;i <= n;++ i)
    		for(int j = 1;j <= n;++ j)
    			c[i][j] = Read();
    	if((k = odd.size()) & 1) {Put(-1,'\n');return 0;}
    	S = n<<1|1; T = S+1; dfs(0,k>>1);
    	Put(ans,'\n');
    	return 0;
    }
    
  • 相关阅读:
    photoshop快捷键汇总
    div和css:行内元素和块元素的水平和垂直居中
    使块元素并排显示和清除浮动的方法
    javascript与DOM节点的结合使用
    导航+轮播图(手动)
    执行计划
    oracle存储过程
    oracle 常用语法
    Sqlserver数据库总结
    sqlserver sum 和count在关于进行统计时的区别
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15881177.html
Copyright © 2020-2023  润新知