Collectors Problem UVA - 10779
网络流·最大流
题目大意:
Bob和他的朋友从糖果包装里收集贴纸。这些朋友每人手里都有一些贴纸(可能重复),并且只跟别人交换他所没有的贴纸。贴纸总是一对一交换。
Bob比这些朋友聪明,因为他意识到只跟别人交换自己没有的贴纸并不总是最优的。
问:Bob最多收集到多少种贴纸?
题解:
把每个人(除Bob)和每种贴纸看成点。
每个贴纸的点向T连1的边,如果有流从这里流过表示可以收集到这种贴纸。
对于除Bob外的每个人,假设他拥有某种贴纸cnt个,
如果cnt>1,从这个人向这种贴纸连cnt-1,表示他最多可以提供cnt-1张。
如果cnt=0,从贴纸向人连边,容量为1,表示他可以接受一个这种他没有的贴纸。
因为人的点流量平衡,也就是
【入流】他得来的(原来他没有的)贴纸的数量
【出流】他被换走的(原来他有超过一张的)贴纸的数量
相等。刚好满足一对一交换。
最后让S代表Bob,向他有的贴纸连cnt的边。这些流量可以直接流向T,也可以用于交换。
最大流即是答案。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 205;
const int M = 1005;
const int INF = 0x3f3f3f3f;
struct Edge{
int to,cap,flow,next;
}e[M*2];
int head[N],ec=1;
void clearEdge(){ memset(head,0,sizeof(head)); ec=1; }
void add(int a,int b,int cap){
ec++; e[ec].to=b; e[ec].cap=cap; e[ec].flow=0;
e[ec].next=head[a]; head[a]=ec;
}
void add2(int a,int b,int cap){
add(a,b,cap); add(b,a,0);
}
int S,T,n,m;
int cnt[N][N];
bool vis[N]; int d[N];
void clearAll(){
memset(cnt,0,sizeof(cnt));
clearEdge();
}
bool bfs(){
memset(vis,0,sizeof(vis));
queue<int> q; q.push(S); vis[S]=true; d[S]=0;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(e[i].cap>e[i].flow && !vis[v]){
d[v]=d[u]+1; vis[v]=true; q.push(v);
}
}
}
return vis[T];
}
int dfs(int u,int a){
if(u==T || a==0) return a;
int flow=0, f;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(d[v]==d[u]+1 && (f=dfs(v,min(a,e[i].cap-e[i].flow)))){
flow+=f; a-=f;
e[i].flow+=f; e[i^1].flow-=f;
if(a==0) break;
}
}
if(a>0) d[u]=-1;
return flow;
}
int dinic(){
int flow=0;
while(bfs()){
flow+=dfs(S,INF);
}
return flow;
}
inline int person(int x){ return x; }
inline int object(int x){ return x+n; }
void build(){
S=n+m+1; T=S+1;
for(int j=1;j<=m;j++){
if(cnt[1][j]) add2(S,object(j),cnt[1][j]);
}
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
if(cnt[i][j]>1) add2(person(i),object(j),cnt[i][j]-1);
else if(cnt[i][j]==0) add2(object(j),person(i),1);
}
}
for(int j=1;j<=m;j++){
add2(object(j),T,1);
}
}
int main(){
freopen("a.in","r",stdin);
int T; cin>>T;
int a,k;
for(int cas=1;cas<=T;cas++){
clearAll();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&k);
while(k--){
scanf("%d",&a);
cnt[i][a]++;
}
}
build();
int ans=dinic();
printf("Case #%d: %d\n",cas,ans);
}
}

本文介绍了一个基于网络流的最大流问题——贴纸收集问题UVA-10779。通过建立特殊的网络模型,利用Dinic算法求解最大流,以确定Bob能收集到的贴纸种类数量。
1312

被折叠的 条评论
为什么被折叠?



