简化一下题意:给出
n
n
n对限制
(
a
i
,
b
i
)
(a_i,b_i)
(ai,bi)代表使用第
a
i
a_i
ai个房间与第
b
i
b_i
bi个菜。每个房间和菜只能使用1次,求最多能满足多少个
(
a
i
,
b
i
)
(a_i,b_i)
(ai,bi). 这不就是匹配问题吗.考虑最大流解决该问题, 边属性:
(
u
,
v
,
c
a
p
)
(u,v,cap)
(u,v,cap) 对于每个客人,建边
(
a
i
,
b
i
,
1
)
(a_i,b_i,1)
(ai,bi,1) 对于房间:
(
s
,
a
i
,
1
)
(s,a_i,1)
(s,ai,1),对食物
(
b
i
,
t
i
,
1
)
(b_i,t_i,1)
(bi,ti,1) 跑
s
,
t
s,t
s,t的最大流就okk. 然而并不okk,上边建的边回导致一个人重复造成贡献,也就是在一个人同时喜欢多个食物,房间的搭配的情况下,它的最大贡献也只能是1. 解决方法:这是网络流中结点容量的限制,把房间的边
(
s
,
a
i
,
1
)
(s,a_i,1)
(s,ai,1)拆成两条边
(
s
,
i
,
1
)
,
(
i
,
i
+
a
i
,
1
)
(s,i,1),(i,i+a_i,1)
(s,i,1),(i,i+ai,1) 可惜,这还是踏马的WA了,直接脑淤血,因为这么做之后,人是唯一的,房间是唯一的,而且食物也要唯一,也就是说,拆三次. 显然,我们有待思考这种拆三次的做法,考虑一下把人作为限制条件,也就是人所造成房间与食物的连边直接拆
大概长这样,这样保证了这三者节点容量最大只能是1.
/*
Stairs upon the temple
I climb and I crawl in
People travel millions of miles just to see it
But they never conquer this way
*/
#include
using namespace std;
const int maxn = 500+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
struct Edge{
int from,to,cap,flow;//起点,终点,容量,流量
};
struct Dicnic{
int n,m,s,t;//点,边,源点,汇点
vector edges;//边集
vector G[maxn];
bool vis[maxn];//bfs 使用的
int d[maxn];//起点到i的距离,就是bfs得到的层次图,下次dfs沿着d走
int cur[maxn];//当前弧优化使用
void addEdge(int from,int to,int cap){
edges.push_back({from,to,cap,0});
edges.push_back({to,from,0,0});//反向边
m = edges.size();
G[from].push_back(m-2);G[to].push_back(m-1);
//正边的编号都是偶数,反向边的编号都是奇数
}
bool bfs(){
memset(vis,0,sizeof(vis));
queue Q;Q.push(s);
d[s]=0;vis[s]=true;
while(!Q.empty()){
int x = Q.front();Q.pop();
for(auto v : G[x]){
Edge &e = edges[v];//获得边的编号
if(!vis[e.to]&&e.cap>e.flow){
//只有未被访问过,而且位于残量网络中的弧才考虑
vis[e.to]=1;
d[e.to]=d[x]+1;Q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
//寻找增广路,a代表目前经过的路中,每个边剩余的流量
if(x==t||a==0) return a;//到达终点/残量为0
int flow = 0,f;
for(int &i = cur[x];i0){
//首先要按层次图走,然后当前增加流量要是增广路中流量最小的的
e.flow+=f;
edges[G[x][i]^1].flow-=f;//正边加流量,反边减流量
flow+=f;a-=f;
if(a==0) break;
}
}
return flow;
}
int Maxflow(int s,int t){
this->s=s;this->t=t;
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));flow+=dfs(s,INF);
}
return flow;
}
}g;
int room[maxn][maxn],food[maxn][maxn];
// i person love room[i][j] or not
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,p,q;
cin>>n>>p>>q;
for(int i=1;iroom[i][j];
if(room[i][j]==1) g.addEdge(j,(p+q+i),1);
}
}
for(int i=1;ifood[i][j];
if(food[i][j]) g.addEdge((p+q+n)+i,p+j,1);
}
}
int s = 0, t = p+q+2*n+5;
for(int i=1;i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?