最大流
Poj 1149 PIGS
为了保证顺序,可以建n列m排点,每个人连ki到T,猪圈连在一起,依次决策。
点数nm。
其实可以更好。
发现其实很多点都是不变的,这样很浪费。
考虑分配的原因,本质是为了后面的人的选择。
所以,
源点到每个猪圈来买的第一个人连一条容量为该猪圈里猪的数量的边
对于每个猪圈,第i个来买的人向第i+1个来买的人连一条容量为正无穷的边
每个人向汇点连一条容量为购买数量的边
这样,每个人的面对的猪圈要么是没有动过的,要么是可能经过之前分配过的。符合题意。
人之间可以直接传递猪。就不用猪圈了。
点数n
扫描二维码关注公众号,回复:
4498711 查看本文章
注意n,m输入,先m后n。
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> #define il inline #define reg register int #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=105; const int M=1005; const int inf=0x3f3f3f3f; int n,m; struct node{ int nxt,to; int w; }e[N*M*2+M*2]; int s,t; int hd[N],cnt=1; void add(int x,int y,int z){ e[++cnt].nxt=hd[x]; e[cnt].to=y; e[cnt].w=z; hd[x]=cnt; e[++cnt].nxt=hd[y]; e[cnt].to=x; e[cnt].w=0; hd[y]=cnt; } int pig[M],vis[M]; int las[M];//las has i 's ren int d[N+3]; int dfs(int x,int flow){ int res=flow; if(x==t) return flow; for(reg i=hd[x];i&&res;i=e[i].nxt){ int y=e[i].to; if(d[y]==d[x]+1&&e[i].w){ int k=dfs(y,min(res,e[i].w)); if(!k) d[y]=0; e[i].w-=k; e[i^1].w+=k; res-=k; } } return flow-res; } int q[N+3]; int l,r; bool bfs(){ l=1,r=0; memset(d,0,sizeof d); q[++r]=s; d[s]=1; while(l<=r){ int x=q[l++]; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(e[i].w&&!d[y]){ d[y]=d[x]+1; q[++r]=y; if(y==t) return true; } } } return false; } int main(){ rd(m);rd(n); for(reg i=1;i<=m;++i) rd(pig[i]); int x,c; s=0,t=n+1; for(reg i=1;i<=n;++i){ rd(c); while(c--){ rd(x); if(!las[x]) add(s,i,pig[x]),las[x]=i; else add(las[x],i,inf),las[x]=i; } rd(c); add(i,t,c); } int flow=0; int ans=0; while(bfs()){ while(flow=dfs(s,inf)) ans+=flow; } printf("%d",ans); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/12/14 7:58:25 */