zoukankan      html  css  js  c++  java
  • 网络流模型之二分图匹配问题

    模型

    给你一些物品,每一个物品都有自己的价值,但是有些物品两两之间会产生冲突,问能选出的物品最大的总价值

    通用的的做法是在两两冲突的物品之间连边

    在建出的图上跑黑白染色

    由源点向所有的白点连边,由所有的黑点向汇点连边,由所有的白点向会与它产生冲突的黑点连边

    跑一个最大流即可

    例题

    [SDOI2016]数字配对

    题目传送门

    分析

    (cnt[i])(a[i]) 分解质因数后质因数所有幂次的和。

    如果 (a[i])(a[j]) 会产生冲突,那么 (cnt[i])(cnt[j]) 的奇偶性一定是相反的。

    所以我们只要把 (cnt) 为奇数的染成白色,把所有 (cnt) 为偶数的染成黑色。

    这样问题就转化为了二分图的模型。

    然后由源点向所有白点连流量为 (b[i]),费用为 (0) 的边。

    由白点向所有会与它产生冲突的黑点连流量为无穷大,费用为对应价值的边。

    黑点同理。

    因为题目中还有价值总和不小于 (0) 的限制。

    所以不能直接跑最大费用最大流。

    要在费用变为 (0) 的时候停止增广。

    因为在增广的过程中费用一定是逐渐变小的。

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=5e4+5;
    int h[maxn],tot=2,n,m,s,t,ans;
    struct asd{
    	int to,nxt,val;
    	long long cost;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc,rg long long dd){
    	b[tot].to=bb;
    	b[tot].val=cc;
    	b[tot].cost=dd;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    long long dis[maxn],ans2;
    int pre[maxn],incf[maxn],ans1;
    bool inq[maxn];
    std::queue<int> q;
    bool spfa(){
    	memset(dis,0xcf,sizeof(dis));
    	memset(pre,0,sizeof(pre));
    	memset(incf,0,sizeof(incf));
    	inq[s]=1,dis[s]=0,incf[s]=0x3f3f3f3f;
    	q.push(s);
    	while(!q.empty()){
    		rg int now=q.front();
    		q.pop();
    		inq[now]=0;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && dis[u]<dis[now]+b[i].cost){
    				dis[u]=dis[now]+b[i].cost;
    				incf[u]=std::min(incf[now],b[i].val);
    				pre[u]=i;
    				if(!inq[u]){
    					inq[u]=1;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return dis[t]!=dis[0];
    }
    void updat(){
    	rg int now=t,i;
    	ans2+=dis[now]*incf[now];
    	if(ans2<0){
    		ans1-=(ans2-dis[now]*incf[now])/dis[now];
    		printf("%d
    ",ans1);
    		std::exit(0);
    	}
    	ans1+=incf[now];
    	while(now!=s){
    		i=pre[now];
    		b[i].val-=incf[t];
    		b[i^1].val+=incf[t];
    		now=b[i^1].to;
    	}
    }
    int jla[maxn],jlb[maxn],jlc[maxn],cnt[maxn];
    int div(rg int now){
    	rg int ncnt=0;
    	for(rg int i=2;i*i<=now;i++){
    		if(now%i==0){
    			while(now%i==0){
    				now/=i;
    				ncnt++;
    			}
    		}
    	}
    	if(now>1) ncnt++;
    	return ncnt;
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	s=n+1,t=n+2;
    	for(rg int i=1;i<=n;i++) jla[i]=read();
    	for(rg int i=1;i<=n;i++) jlb[i]=read();
    	for(rg int i=1;i<=n;i++) jlc[i]=read();
    	for(rg int i=1;i<=n;i++) cnt[i]=div(jla[i]);
    	for(rg int i=1;i<=n;i++){
    		if(cnt[i]&1){
    			ad(s,i,jlb[i],0);
    			ad(i,s,0,0);
    		} else {
    			ad(i,t,jlb[i],0);
    			ad(t,i,0,0);
    		}
    	}
    	for(rg int i=1;i<=n;i++){
    		if(cnt[i]&1){
    			for(rg int j=1;j<=n;j++){
    				if(cnt[j]&1) continue;
    				if((cnt[i]==cnt[j]+1 && jla[i]%jla[j]==0) || (cnt[j]==cnt[i]+1 && jla[j]%jla[i]==0)){
    					ad(i,j,0x3f3f3f3f,1LL*jlc[i]*jlc[j]);
    					ad(j,i,0,-1LL*jlc[i]*jlc[j]);
    				}
    			}
    		}
    	}
    	while(spfa()) updat();
    	printf("%d
    ",ans1);
    	return 0;
    }
    

    bzoj3158千钧一发

    题目传送门

    分析

    可以证明,任意两个偶数满足 (2)

    任意两个奇数满足 (1)

    ((2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1))

    一定不是完全平方数,因为括号里的东西显然是一个奇数,不能再分出一个 (2)

    所以可以把奇数作为白点,偶数作为黑点

    跑一个最小割就行了

    代码

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<map>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5;
    int h[maxn],h2[maxn],tot=2,s,t;
    std::map<int,int> mp[maxn],id[maxn];
    struct asd{
    	int to,nxt,val;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	b[tot].val=cc;
    	h[aa]=tot++;
    }
    int q[maxn],head,tail,dep[maxn],mmax;
    bool bfs(){
    	for(rg int i=1;i<=mmax;i++){
    		h[i]=h2[i];
    		dep[i]=0;
    	}
    	q[head=tail=1]=s;
    	dep[s]=1;
    	while(head<=tail){
    		rg int now=q[head++];
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && !dep[u]){
    				dep[u]=dep[now]+1;
    				q[++tail]=u;
    			}
    		}
    	}
    	return dep[t]!=0;
    }
    int dfs(rg int now,rg int ac1){
    	if(now==t) return ac1;
    	rg int ac2=0;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		h[now]=i;
    		rg int u=b[i].to;
    		if(b[i].val && dep[u]==dep[now]+1){
    			rg int nans=dfs(u,std::min(b[i].val,ac1));
    			b[i].val-=nans;
    			b[i^1].val+=nans;
    			ac1-=nans;
    			ac2+=nans;
    		}
    		if(ac1==0) break;
    	}
    	if(ac2==0) dep[now]=0;
    	return ac2;
    }
    int n,a[maxn],val[maxn];
    bool jud(rg long long val){
    	rg long long sqr=sqrt(val);
    	return sqr*sqr==val;
    }
    int gcd(rg int aa,rg int bb){
    	return bb==0?aa:gcd(bb,aa%bb);
    }
    int ans=0,col[maxn];
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	s=n+1,t=n+2,mmax=n+2;
    	for(rg int i=1;i<=n;i++){
    		a[i]=read();
    	}
    	for(rg int i=1;i<=n;i++){
    		val[i]=read();
    		ans+=val[i];
    		if(a[i]&1){
    			ad(s,i,val[i]);
    			ad(i,s,0);
    		} else {
    			ad(i,t,val[i]);
    			ad(t,i,0);
    		}
    	}
    	for(rg int i=1;i<=n;i++){
    		if(a[i]&1){
    			for(rg int j=1;j<=n;j++){
    				if((a[j]&1)==0){
    					if(jud(1LL*a[i]*a[i]+1LL*a[j]*a[j]) && gcd(a[i],a[j])==1){
    						ad(i,j,0x3f3f3f3f);
    						ad(j,i,0);
    					}
    				}
    			}
    		}
    	}
    	for(rg int i=1;i<=mmax;i++) h2[i]=h[i];
    	while(bfs()) ans-=dfs(s,0x3f3f3f3f);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ajax调接口示例
    JQuery的ready函数与JS的onload的区别详解
    DIV拖拽
    Lasso估计学习笔记(二)
    Lasso估计论文学习笔记(一)
    ubuntu下部署mongodb以及设置允许远程连接
    C#获取Honeywell voyager 1400g扫码后的数据
    vs2015“当前不会命中断点 还没有为该文档加载任何符号”的解决方法
    pyqt4 python2.7 中文乱码的解决方法
    使用pip 提示UnicodeDecodeError: 'ascii' codec can't decode解决方法
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14331436.html
Copyright © 2011-2022 走看看