基本规律:
规律1. 如果几个结点的流量的来源完全相同,则可以把它们合并成一个。
规律2. 如果几个结点的流量的去向完全相同,则可以把它们合并成一个。
规律3. 如果从点u到点v有一条容量为∞的边,并且点v除了点u以外没有别的流量来源,则可以把这两个结点合并成一个。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn = 205; const int INF = 0x3f3f3f3f; int cap[maxn][maxn]; int flow[maxn][maxn]; int ansf; int n; int s,t; void EK(){ ansf = 0; int p[maxn]; memset(flow,0,sizeof(flow)); queue<int> Q; while(!Q.empty()) Q.pop(); int res[maxn]; while(true){ memset(p,0,sizeof(p)); p[s] = s; memset(res,0,sizeof(res)); res[s] = INF; Q.push(s); while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int v=1;v<=n+1;v++){ if(!res[v] && cap[u][v] > flow[u][v]){ p[v] = u; Q.push(v); res[v] = min(res[u],cap[u][v] - flow[u][v]); //printf("%d %d\n",u,res[v]); } } } //printf("*** %d\n",res[t]); if(res[t] == 0) break; for(int i=t;i!=s;i=p[i]){ flow[p[i]][i] += res[t]; flow[i][p[i]] -= res[t]; } ansf += res[t]; //printf("HH** %d\n",ansf); } return; } int main() { //if(freopen("input.txt","r",stdin)== NULL) {printf("Error\n"); exit(0);} int N,M,A; cin>>M>>N; s = 0; t = N+1; n = N ; memset(cap,0,sizeof(cap)); int c[1005]; for(int i=1;i<=M;i++){ cin>>c[i]; } int d[maxn]; int a[1005]; memset(a,0,sizeof(a)); for(int i=1;i<=N;i++){ cin>>A; for(int j=1;j<=A;j++){ int b; cin>>b; if(!a[b]){ cap[s][i] += c[b]; a[b] = i; } else{ cap[a[b]][i] = INF; a[b] = i; } } cin>>d[i]; } for(int i=1;i<=N;i++){ cap[i][t] = d[i]; } EK(); printf("%d\n",ansf); return 0; }