zoukankan      html  css  js  c++  java
  • P4068 [SDOI2016]数字配对

    题意描述:

    洛谷

    (n) 个数字,每个数字的权值为 (a_i), 有 (b_i) 个,价值为 (c_i)

    如果 (a_i)(a_j) 的倍数,且 (a_i /a_j) 为质数,则称 (a_i)(a_j) 可以配对成功,价值为 (c_i imes c_j)

    每个数字只能匹配一次。 在获得的总价值不大于 (0) 的情况下,最多能匹配多少次。

    数据范围: (nleq 200,a_ileq 10^9,|c_i|leq 10^5)

    solution:

    最大费用最大流。

    每个数字只能匹配一次,且个数有限制,每次匹配有价值,很容易想到费用流求解。

    把每一次匹配当成一个流量,价值就是匹配所得到的价值。

    然后 对于能成功匹配的 (i)(j) 两点之间连一条容量为 (inf), 费用为 (c_i imes c_j) 的边。

    但我们不能确定每个数是位于左边还是右边。

    比价笨的办法就是在跑 (dinic) 之前,跑一遍二分图染色。

    对于左侧的点 (i),由源点向 (i) 连一条容量为 (a_i) 费用为 (0) 的边,反之位于右侧的点,则由点 (i) 向汇点连容量为 (a_i) 费用为 (0) 的边。

    直接跑最大费用最大流肯定不对,因为求的是费用非负时的最大流。

    考虑贪心一波,假设我们这次增广路的流量为 (flow[t]) ,单位费为 (dis[t]) ,当前收益为 (maxcost) .

    如果 (dis[t] >0) ,很显然这样的匹配肯定是流量越多越好。

    如果 (dis[t] < 0) 我们每次匹配是要损失一些代价的,当前收益最多能支持我们进行的匹配次数为 (min(flow[t],{maxcostover -dis[t]})) , 答案直接加上这个次数即可。

    如果 (maxcost < 0) 即费用为负,不能再继续匹配下去了,直接 (break) 掉。

    code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    using namespace std;
    #define int long long
    const int inf = 1e18;
    const int N = 1e5+10;
    int n,maxflow,maxcost,s,t,tot = 1;
    int head[N],a[N],b[N],c[N],dis[N],flow[N],pre[N],last[N],col[N];
    bool vis[N],check[510][510];
    struct node
    {
    	int to,net,w,c;
    }e[2000010];
    inline int read()
    {
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    void add(int x,int y,int w,int c)
    {
    	e[++tot].to = y;
    	e[tot].w = w;
    	e[tot].c = c;
    	e[tot].net = head[x];
    	head[x] = tot;
    }
    bool pd(int x)
    {
    	for(int i = 2; i <= sqrt(x); i++)
    	{
    		if(x % i == 0) return 0;	
    	} 
    	return 1;
    } 
    void dfs(int x,int w)
    {
    	col[x] = w;
    	if(w == 1) add(s,x,b[x],0), add(x,s,0,0);
    	else add(x,t,b[x],0), add(t,x,0,0);
    	for(int i = 1; i <= n; i++)
    	{
    		if(check[x][i] && !col[i]) dfs(i,3-w); 
    	}
    }
    bool spfa()
    {
    	queue<int> q;
    	for(int i = 0; i <= t; i++) dis[i] = -inf, flow[i] = inf;
    	for(int i = 0; i <= t; i++) vis[i] = 0, pre[i] = last[i] = -1;
    	q.push(s); dis[s] = 0, vis[s] = 1;
    	while(!q.empty())
    	{
    		int x = q.front(); q.pop(); vis[x] = 0;
    		for(int i = head[x]; i; i = e[i].net)
    		{
    			int to = e[i].to;
    			if(e[i].w && dis[to] < dis[x] + e[i].c)
    			{
    				dis[to] = dis[x] + e[i].c;
    				flow[to] = min(flow[x],e[i].w);
    				pre[to] = x, last[to] = i; 
    				if(!vis[to]){q.push(to); vis[to] = 1;}
    			} 
    		}
    	} 
    	return pre[t] != -1;
    }
    void mcmf()
    {
    	while(spfa())
    	{
    		maxcost += flow[t] * dis[t];
    		maxflow += flow[t];
    		if(maxcost < 0)
    		{
    			maxcost -= flow[t] * dis[t];
    			maxflow -= flow[t];
    			maxflow += maxcost / (-dis[t]);
    			break;
    		}
    		int x = t;
    		while(x)
    		{
    			e[last[x]].w -= flow[t];
    			e[last[x] ^ 1].w += flow[t];
    			x = pre[x];
    		}
    	}
    }
    signed main()
    {
    	n = read();
    	for(int i = 1; i <= n; i++) a[i] = read();
    	for(int i = 1; i <= n; i++) b[i] = read();
    	for(int i = 1; i <= n; i++) c[i] = read();
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(i == j) continue;
    			if((a[i] % a[j] == 0 && pd(a[i]/a[j]))) check[i][j] = check[j][i] = 1;
    		}
    	}
    	s = 0, t = n+1;
    	for(int i = 1; i <= n; i++) if(!col[i]) dfs(i,1); 
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(col[i] == 1 && check[i][j]) add(i,j,inf,c[i]*c[j]), add(j,i,0,-c[i]*c[j]);
    		}
    	}
    	mcmf();
    	printf("%lld
    ",maxflow);
    	return 0;
    }
    
  • 相关阅读:
    Using Resource File on DotNet
    C++/CLI VS CSharp
    JIT VS NGen
    [Tip: disable vc intellisense]VS2008 VC Intelisense issue
    UVa 10891 Game of Sum(经典博弈区间DP)
    UVa 10723 Cyborg Genes(LCS变种)
    UVa 607 Scheduling Lectures(简单DP)
    UVa 10401 Injured Queen Problem(简单DP)
    UVa 10313 Pay the Price(类似数字分解DP)
    UVa 10635 Prince and Princess(LCS N*logN)
  • 原文地址:https://www.cnblogs.com/genshy/p/14409692.html
Copyright © 2011-2022 走看看