Codeforces Round #147 (Div. 2) E. Build String 最小费用最大流
http://codeforces.com/problemset/problem/237/E
题意:给定一个目标字符串,然后给你n个字符串,从这n个字符串里面s1,s2,...sn,抽出字符组成目标字符串,每个字符串都对应这最多可以抽出a[i]个字符,抽取每个字符都有一定的费用,抽si里面的字符的话,每个字符需要i的钱数,判断目标字符串是否能够从这n个字符串里面抽出字符组成,若可以输出最小的费用,否则输出-1;
思路:最小费用最大流。说实话看到这个题目时,真没网网络流方向想,比赛时时间也不够了,赛后一看tags 显示flows 才豁然开朗。 网流的题目关键还是能够看出如何建图,然后直接套模板即可。 建立源点s 汇点 e
s ---(1 - n)间边流量为a[i](每个字符串最多可抽取的字符数)权值为0 --> (1 +n ,1 + desl)目标字符中出现的字符 流量min(字符串i具有的des[j]字符的个数,a[i]) 权值为i -->e 流量为目标串需要的字符的个数,权值为0
View Code
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 150 #define N 107 using namespace std; //freopen("data.in","r",stdin); int c[M][M],w[M][M]; char inp[N],str[N][N],des[27]; int hash[27],num[27],a[N]; int pre[M],dis[M],vt[M]; int n,tol; void spfa(int s,int e){ int i; for (i = s; i <= e; ++i){ dis[i] = inf; vt[i] = 0; pre[i] = -1; } queue<int>q; q.push(s); vt[s] = 1; dis[s] = 0; while (!q.empty()){ int u = q.front(); q.pop(); for (i = s; i <= e; ++i){ if (c[u][i] > 0 && dis[i] > dis[u] + w[u][i]){ dis[i] = dis[u] + w[u][i]; pre[i] = u; if (!vt[i]){ q.push(i); vt[i] = 1; } } } vt[u] = 0; } } int mcmf(int s,int e){ int ans = 0; int flows = 0; int i; while (1){ spfa(s,e); if (pre[e] == -1) break; int x = e; int MIN = inf; for (i = pre[x]; i != -1; i = pre[i]){ MIN = min(MIN,c[i][x]); x = i; } flows += MIN; x = e; for (i = pre[x]; i != -1; i = pre[i]){ c[i][x] -= MIN; c[x][i] += MIN; ans += w[i][x]*MIN; x = i; } } if (tol == flows) return ans; else return -1; } int main(){ //freopen("data.in","r",stdin); int i,j,k; scanf("%s",inp); CL(hash,0); CL(num,0); int len = strlen(inp); int desl = 0; for (i = 0; i < len; ++i){ int mk = inp[i] - 'a'; if (!hash[mk]){ des[++desl] = mk; num[desl]++; hash[mk] = 1; } else{ for (j = 1; j <= desl; ++j){ if (des[j] == mk){ num[j]++; break; } } } } tol = 0; for (i = 1; i <= desl; ++i) tol += num[i]; scanf("%d",&n); for (i = 1; i <= n; ++i){ scanf("%s %d",str[i],&a[i]); } int s = 0,e = n + desl + 1; CL(c,0); CL(w,0); for (i = 1; i <= n; ++i){ c[s][i] = a[i]; c[i][s] = 0; w[s][i] = w[i][s] = 0; } for (j = n + 1; j <= n + desl; ++j){ c[j][e] = num[j - n]; c[e][j] = 0; w[j][e] = w[e][j] = 0; } for (i = 1; i <= n; ++i){ int len = strlen(str[i]); for (j = 1; j <= desl; ++j){ int ct = 0; for (k = 0; k < len; ++k){ if (str[i][k] - 'a' == des[j]) ct++; } c[i][j + n] = min(ct,a[i]); c[j + n][i] = 0; w[i][j + n] = i; w[j + n][i] = -i; } } printf("%d\n",mcmf(s,e)); return 0; }