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;
}

 

posted @ 2012-10-26 22:05  E_star  阅读(277)  评论(0编辑  收藏  举报