博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【LA3487】最小割-经典模型 两种方法
阅读量:4963 次
发布时间:2019-06-12

本文共 4589 字,大约阅读时间需要 15 分钟。

题意:A、B两个公司要买一些资源(他们自己买的资源不会重复),一个资源只能卖给一个公司。问最大收益。

simple input 部分:

54 1 //买到1就给54元

15 2

33 3

2 4 5//买到4、5就给2元

 

题解:这道题是很经典的模型题,在这里给出两个方法。

方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。

// 方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个// 询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。#include
#include
#include
#include
#include
#include
using namespace std;const int N=300100,INF=(int)1e9;int s,t,len,num;int first[2*N],dis[2*N];int A[N],B[N],p1[N],p2[N];// bool vis[2*N];bool vis[3100][3100];struct node{ int x,y,d,next;}a[6*N];queue
q;int minn(int x,int y){ return x
y ? x:y;}void ins(int x,int y,int d){ a[++len].x=x;a[len].y=y;a[len].d=d; a[len].next=first[x];first[x]=len; a[++len].x=y;a[len].y=x;a[len].d=0; a[len].next=first[y];first[y]=len;}bool bfs(int st,int ed){ while(!q.empty()) q.pop(); memset(dis,-1,sizeof(dis)); dis[st]=0; q.push(st); while(!q.empty()) { int x=q.front();q.pop(); for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(dis[y]==-1 && a[i].d>0) { dis[y]=dis[x]+1; q.push(y); } } } return (dis[ed]!=-1);}int dfs(int x,int ed,int flow){ int r=0,p; if(x==ed) return flow; for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(dis[y]==dis[x]+1 && a[i].d>0) { p=minn(a[i].d,flow-r); p=dfs(y,ed,p); r+=p; a[i].d-=p; a[i^1].d+=p; } } if(!r) dis[x]=-1; return r;}int dinic(int st,int ed){ int ans=0; while(bfs(st,ed)) { int p; while(p=dfs(st,ed,INF)) ans+=p; } return ans;}int main(){ int T,cas=0; scanf("%d",&T); while(T--) { len=-1; memset(first,-1,sizeof(first)); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(vis,0,sizeof(vis)); int n,m,sum=0,mx=0,num=300001; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&p1[i]); sum+=p1[i]; int x;num++; while(1) { char c; scanf("%d%c",&x,&c); A[x]=i; mx=maxx(mx,x); if(c=='\n') break; } } scanf("%d",&m); s=0,t=n+m+1; for(int i=1;i<=m;i++) { scanf("%d",&p2[i]); sum+=p2[i];num++; int x; while(1) { char c; scanf("%d%c",&x,&c); B[x]=i; mx=maxx(mx,x); if(c=='\n') break; } } for(int i=1;i<=n;i++) ins(s,i,p1[i]); for(int i=1;i<=m;i++) ins(i+n,t,p2[i]); for(int i=1;i<=mx;i++) { if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue; vis[A[i]][B[i]]=true; ins(A[i],B[i]+n,INF); } printf("Case %d:\n",++cas); printf("%d\n",sum-dinic(s,t)); if(T) printf("\n"); } return 0;}
方法一

 

方法二:对于每个询问,新建一个点x,如果是A就源点连向这个点,流量为价钱p,然后x连向这个询问所要求买的资源c[i],流量为INF。

如果是B则反过来,连向汇点。

#include
#include
#include
#include
#include
#include
using namespace std;const int N=300100,INF=(int)1e9;int s,t,len,num;int first[2*N],dis[2*N];int A[N],B[N];bool vis[3100][3100];struct node{ int x,y,d,next;}a[6*N];queue
q;int minn(int x,int y){ return x
y ? x:y;}void ins(int x,int y,int d){ a[++len].x=x;a[len].y=y;a[len].d=d; a[len].next=first[x];first[x]=len; a[++len].x=y;a[len].y=x;a[len].d=0; a[len].next=first[y];first[y]=len;}bool bfs(int st,int ed){ while(!q.empty()) q.pop(); memset(dis,-1,sizeof(dis)); dis[st]=0; q.push(st); while(!q.empty()) { int x=q.front();q.pop(); for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(dis[y]==-1 && a[i].d>0) { dis[y]=dis[x]+1; q.push(y); } } } return (dis[ed]!=-1);}int dfs(int x,int ed,int flow){ int r=0,p; if(x==ed) return flow; for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(dis[y]==dis[x]+1 && a[i].d>0) { p=minn(a[i].d,flow-r); p=dfs(y,ed,p); r+=p; a[i].d-=p; a[i^1].d+=p; } } if(!r) dis[x]=-1; return r;}int dinic(int st,int ed){ int ans=0; while(bfs(st,ed)) { int p; while(p=dfs(st,ed,INF)) ans+=p; } return ans;}int main(){ int T,cas=0; scanf("%d",&T); while(T--) { len=-1; memset(first,-1,sizeof(first)); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(vis,0,sizeof(vis)); int n,m,p,sum=0,mx=0,num=300001; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&p); sum+=p; int x;num++; ins(0,num,p); while(1) { char c; scanf("%d%c",&x,&c); ins(num,x+1,INF); if(c=='\n') break; } } scanf("%d",&m); s=0,t=1; for(int i=1;i<=m;i++) { scanf("%d",&p); sum+=p;num++; ins(num,t,p); int x; while(1) { char c; scanf("%d%c",&x,&c); ins(x+1,num,INF); if(c=='\n') break; } } for(int i=1;i<=n;i++) ins(s,i,p1[i]); for(int i=1;i<=m;i++) ins(i+n,t,p2[i]); for(int i=1;i<=mx;i++) { if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue; vis[A[i]][B[i]]=true; ins(A[i],B[i]+n,INF); } printf("Case %d:\n",++cas); printf("%d\n",sum-dinic(s,t)); if(T) printf("\n"); } return 0;}
方法二

 

转载于:https://www.cnblogs.com/KonjakJuruo/p/5516479.html

你可能感兴趣的文章
什么是平衡二叉树(AVL)
查看>>
阿里云搭建LAMP环境详细教程
查看>>
atitit.农历的公式与原理以及农历日期运算
查看>>
ES6 之 第七种数据类型Symbol
查看>>
spring data mongodb 配置遇到的几个问题
查看>>
Flume-ng源码解析之Channel组件
查看>>
技术博客
查看>>
设计模式之工厂方法模式
查看>>
在Lua里写unity游戏笔记
查看>>
Maven项目搭建(二):Maven搭建SSM框架
查看>>
我常用的delphi 第三方控件
查看>>
jQuery序列化表单 serialize() serializeArray()
查看>>
java python oracle推断字符串是否为数字的函数
查看>>
Ruby On Rails 4 hello world,Ruby On Rails上手
查看>>
linux杂谈(二十):apache服务配置
查看>>
FastDFS的配置、部署与API使用解读(6)FastDFS配置详解之Storage配置
查看>>
善用#waring,#pragma mark 标记
查看>>
Android 设置启动界面
查看>>
oracle常用命令
查看>>
超级干货 :一文读懂数据可视化 ZT
查看>>