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;

}

 

你可能感兴趣的:(codeforces)