题意:
给定$M$个猪圈,一开始这些都是上了锁的;
现在$Mike$知道所有要来买猪的顾客的信息:
$1.$顾客拥有的钥匙。
$2.$顾客想要购买的数量。
销售过程为:当每个顾客到来的时候,他将他拥有钥匙的猪圈全部打开,$Mike$从这些猪圈中挑选一些猪卖给他们;
如果$Mike$愿意,他可以重新分配这些被打开的猪圈中的猪,顾客离开时,这些猪圈将被再次锁上,计算$Mike$卖出猪的最大数目。
思路:
设定超级源点和汇点,然后将第一次访问该猪圈的顾客与源点相连,流量为猪圈中猪的数目
顾客$x$紧跟顾客$y$之后打开某个猪圈,那么就将两者相连,流量为$inf$(因为在这之前$Mike$有机会调整)
将每个顾客与汇点相连,流量为改顾客想买的猪的数量。
1 /* 2 * Author: windystreet 3 * Date : 2018-08-16 11:29:37 4 * Motto : Think twice, code once. 5 */ 6 #include <stdio.h> 7 #include <algorithm> 8 #include <string.h> 9 #include <vector> 10 #include <queue> 11 12 using namespace std; 13 14 #define X first 15 #define Y second 16 #define eps 1e-5 17 #define gcd __gcd 18 #define pb push_back 19 #define PI acos(-1.0) 20 #define lowbit(x) (x)&(-x) 21 #define bug printf("!!!!! "); 22 #define mem(x,y) memset(x,y,sizeof(x)) 23 24 typedef long long LL; 25 typedef long double LD; 26 typedef pair<int,int> pii; 27 typedef unsigned long long uLL; 28 29 const int maxn = 1e3+7; 30 const int INF = 1<<30; 31 const int mod = 1e9+7; 32 struct Edge{ 33 int from,to,cap,flow; 34 }; 35 int f[maxn]; // 记录前一个访问过该猪圈的人 36 int pig[maxn]; // 记录每个猪圈原来有多少猪 37 vector<int>v[maxn]; // 记录每个人有的钥匙 38 struct Dinic 39 { 40 int n,m,s,t; 41 vector<Edge>edge; 42 vector<int>G[maxn]; 43 bool vis[maxn]; 44 int d[maxn]; 45 int cur[maxn]; 46 void init(int n){ 47 this->n = n; 48 for(int i=0;i<=n;i++)G[i].clear(),edge.clear(); 49 } 50 inline void addedge(int from,int to,int cap){ 51 edge.pb((Edge){from,to,cap,0}); 52 edge.pb((Edge){to,from,0,0}); 53 m = edge.size(); 54 G[from].pb(m-2); 55 G[to].pb(m-1); 56 } 57 inline bool bfs(){ 58 mem(vis,0); 59 queue<int>Q; 60 Q.push(s); 61 d[s] = 0; 62 vis[s] = 1; 63 while(!Q.empty()){ 64 int x = Q.front(); Q.pop(); 65 int sz = G[x].size(); 66 for(int i=0;i<sz;++i){ 67 Edge &e = edge[G[x][i]]; 68 if(!vis[e.to] && e.cap>e.flow){ 69 vis[e.to] = 1 ; 70 d[e.to] = d[x] + 1; 71 Q.push(e.to); 72 } 73 } 74 } 75 return vis[t]; 76 } 77 int dfs(int x,int a){ 78 if(x == t || a == 0)return a; 79 int flow = 0,f; 80 int sz = G[x].size(); 81 for(int &i = cur[x];i<sz;i++){ 82 Edge &e = edge[G[x][i]]; 83 if(d[x] + 1 == d[e.to] && (f = dfs(e.to,min(a,e.cap - e.flow)))>0){ 84 e.flow += f; 85 edge[G[x][i]^1].flow -=f; 86 flow += f; 87 a -= f; 88 if(a==0)break; 89 } 90 } 91 //if(!flow) d[x] = -2; //炸点优化 92 return flow; 93 } 94 inline int maxflow(int s,int t){ 95 this->s = s; this -> t = t; 96 int flow = 0; 97 while(bfs()){ 98 mem(cur,0); 99 flow += dfs(s,INF); 100 } 101 return flow; 102 } 103 }; 104 Dinic dinic; 105 106 void solve(){ 107 int n,m,x,y; 108 scanf("%d%d",&m,&n); 109 int S = 0,T = n +1; 110 for(int i=1;i<=m;i++)scanf("%d",pig+i); 111 for(int i=1;i<=n;i++){ 112 scanf("%d",&x); 113 while(x--){ 114 scanf("%d",&y); 115 v[i].pb(y); // 记录钥匙 116 } 117 scanf("%d",&y); 118 dinic.addedge(i,T,y); // 将每个人与汇点相连,流量为他需要买的猪 119 } 120 for(int i=1;i<=n;i++){ 121 int sz = v[i].size(); 122 for(int j=0;j<sz;j++){ 123 int id = v[i][j]; 124 if(!f[id]){ // 若没有被访问过,则将该人和源点相连 125 f[id] = i; 126 dinic.addedge(S,i,pig[id]); 127 }else{ 128 dinic.addedge(f[id],i,INF); 129 f[id] = i; // 否则就将其与上一个访问的人相连 130 } 131 } 132 } 133 printf("%d ",dinic.maxflow(S,T)); 134 135 return; 136 } 137 138 int main() 139 { 140 // freopen("F:\in.txt","r",stdin); 141 // freopen("out.txt","w",stdout); 142 // ios::sync_with_stdio(false); 143 int t = 1; 144 //scanf("%d",&t); 145 while(t--){ 146 // printf("Case %d: ",cas++); 147 solve(); 148 } 149 return 0; 150 }