• 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;
    }
    
  • 相关阅读:
    学习smali
    android XML解析器全解案例
    android text中显示HTML语言
    Viewpager图片自动轮播,网络图片加载,图片自动刷新
    Android TextView内容过长加省略号,点击显示全部内容
    Android 反编译 代码注入之HelloWorld
    APK软件反编译 去广告
    【HACK】破解APK并注入自己的代码
    apk反编译生成程序的源代码和图片、XML配置、语言资源等文件
    LA 3905 Meteor
  • 原文地址:https://www.cnblogs.com/genshy/p/14409692.html
Copyright © 2020-2023  润新知