文章目录
- 题目描述
- 数据范围
- 解析
- 代码
题目描述
尼克在一家养猪场工作,这家养猪场共有MMM间锁起来的猪舍,由于猪舍的钥匙都给了客户,所以尼克没有办法打开这些猪舍。有NNN个客户从早上开始一个接一个来购买生猪,他们到达后首先用手中的钥匙打开他所能打开的全部猪舍,然后从中选取他要买的猪,尼克可以在此期间将打开的猪舍中的猪调整到其它开着的猪舍中,每个猪舍能存放的猪的数量是没有任何限制的。买完猪后客户会将他打开的猪舍关上。
好在尼克事先知道每位客户手中有哪些钥匙,要买多少猪,以及客户到来的先后次序。请你写一个程序,帮助尼克求出最多能卖出多少头猪。
数据范围
M<=1000,N<=100M<=1000,N<=100M<=1000,N<=100
解析
关键在于建图的方法
直观感觉是把客户和他能开的猪圈连不限流的双向边,但是会出现时光倒流的bug
我的解决办法是只让猪圈和顾客连边,然后顾客按先后顺序暴力判断猪圈有交集则连一条单向不限流的边
但这样的理论最差边数是n2n^2n2,再加上点数为m,1e3级别,最差情况下 m2∗n2m^2*n^2m2∗n2似乎无法通过
然而实际上59ms跑的飞快
所以网络流一定要敢写
一个比较巧妙的建图方式是把猪圈x连向第一个打开x的顾客,以后再有打开x的顾客k,就从上一个打开x的顾客lst连一条到k的不限流的边
很巧妙
不过边数最差似乎还变成了n*m,更差了…
代码
(因为似乎没有实质的优化,所以还是暴力建图的码)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1205;
const int M=1e9;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,s,t,num;
struct node{int to,nxt,cap;
}p[N*N*2];
int fi[N],cnt;
void addline(int x,int y,int cap){p[++cnt]=(node){y,fi[x],cap};fi[x]=cnt;p[++cnt]=(node){x,fi[y],0};fi[y]=cnt;
}
int col[N],cur[N];
queue<int>q;
int bfs(){memset(col,0,sizeof(col));col[s]=1;q.push(s);while(!q.empty()){int now=q.front();q.pop();for(int i=cur[now]=fi[now];~i;i=p[i].nxt){int to=p[i].to;if(col[to]||!p[i].cap) continue;col[to]=col[now]+1;q.push(to);}}return col[t];
}
int dfs(int x,int lim){if(x==t||!lim) return lim;int res=0;for(int &i=cur[x];~i&&lim;i=p[i].nxt){int to=p[i].to;if(!p[i].cap||col[to]!=col[x]+1) continue;int add=dfs(to,min(lim,p[i].cap));res+=add;lim-=add;p[i].cap-=add;p[i^1].cap+=add;if(!lim) break;}if(!res) col[x]=-1;return res;
}
int dinic(){int tot=0;while(bfs()){while(int tmp=dfs(1,2e9)) tot+=tmp;}return tot;
}
int key[106][1005],tot[106],need[106],id[106];
bool vis[1005];
bool ok(int x,int y){memset(vis,0,sizeof(vis));for(int i=1;i<=tot[x];i++) vis[key[x][i]]=1;for(int i=1;i<=tot[y];i++) if(vis[key[y][i]]) return true;return false;
}
int main(){memset(fi,-1,sizeof(fi));cnt=-1;m=read();n=read();s=++num;t=++num;for(int i=1;i<=m;i++){int x=read();++num;addline(s,num,x);}for(int i=1;i<=n;i++){tot[i]=read();id[i]=++num;for(int j=1;j<=tot[i];j++){key[i][j]=read();addline(key[i][j]+2,num,2e9);}need[i]=read();addline(num,t,need[i]);}for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){if(ok(i,j)) addline(id[i],id[j],2e9);}}printf("%d",dinic());return 0;
}