SP4063 MPIGS - Sell Pigs
SP4063 MPIGS - Sell Pigs
思路
网络流好题。
发现人的要求和猪圈中猪的数量直接处理不好建图,于是考虑对每个人和每个猪圈拆点建图。
具体来说,将每个人拆成两个点,流量为他要购买的猪的数量,将每个猪圈拆成两个点,流量为猪圈中猪的数量。
由于有多个顾客和猪圈,所以考虑建立超级源点与汇点,流向便为源点流向每个人,每个人流向猪圈,猪圈流向汇点。
建边时将源点与每个人的起始点连边,将每个人的结束点与他有钥匙的猪圈的起始点连边,将猪圈的结束点与汇点连边,流量均为无限大,跑一遍最大流即可。然后你就会发现样例都没过。
哪里错了?因为每个人还可以调整每个猪圈中猪的数量,所以每个人的结束点不仅要跟猪圈连边,还要跟之前能到达这个猪圈的人连边,这样可以使得这个人的流可以流到之前顾客能解锁的猪圈中的猪,也就保证了之前的顾客能够调整这个猪圈中猪的数量。
考虑样例:
3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6
建图如下:

代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2205,INF=0x3f3f3f3f;
struct node{
int x,w,rev;
};
vector<node> t[MAXN];
int dep[MAXN],gap[MAXN],maxflow;
int n,S,T;
void add(int x,int y,int w){
t[x].push_back({y,w,t[y].size()});
t[y].push_back({x,0,t[x].size()-1});
}
void bfs(){
memset(gap,0,sizeof(gap));
memset(dep,-1,sizeof(dep));
queue<int> q;
q.push(T),dep[T]=0,gap[dep[T]]++;
while(!q.empty()){
int u=q.front();q.pop();
for(node v:t[u]){
if(dep[v.x]==-1){
dep[v.x]=dep[u]+1;
gap[dep[v.x]]++,q.push(v.x);
}
}
}
}
int dfs(int x,int flow){
if(x==T){
maxflow+=flow;
return flow;
}
int used=0;
for(int i=0;i<t[x].size();i++){
int v=t[x][i].x;
if(t[x][i].w&&dep[v]+1==dep[x]){
int mn=dfs(v,min(t[x][i].w,flow-used));
if(mn) t[x][i].w-=mn,t[v][t[x][i].rev].w+=mn,used+=mn;
if(flow==used) return used;
}
}
if(!(--gap[dep[x]])) dep[S]=n+1;
dep[x]++,gap[dep[x]]++;
return used;
}
int isap(){
maxflow=0;
bfs();
while(dep[S]<n) dfs(S,INF);
return maxflow;
}
vector<int> vis[1005];
int N,M;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>M>>N;
n=2*N+2*M+2;
S=2*N+2*M+1,T=2*N+2*M+2;
for(int x,i=1;i<=M;i++){
cin>>x;
add(2*N+i,2*N+M+i,x);
add(2*N+M+i,T,INF);
}
bool vis2[105];
for(int x,y,i=1;i<=N;i++){
cin>>x;
memset(vis2,0,sizeof(vis2));
while(x--){
cin>>y;
for(int v:vis[y])
if(!vis2[v]){
vis2[v]=true;
add(N+i,N+v,INF);
}
vis[y].push_back(i);
add(N+i,2*N+y,INF);
}
cin>>x,add(S,i,INF),add(i,N+i,x);
}
cout<<isap();
return 0;
}

浙公网安备 33010602011771号