比较裸的费用流吧。(刚好把板子打了一遍)

源点向每个字符连边,流量为要构造的字符串的字符个数,费用为0。

每个字符向每个字符串连边,流量为这个字符串中这个字符出现的次数,费用为i。

每个字符串向汇点连边,流量为每个字符串的限制,费用为0。

然后跑费用流,判断是否满流,如果不是就无解,是就输出花费。

#include<cstdio>  
#include<cstring>
#define S 0
#define T 500
struct edge{  
    int to,cap,rev,nx,we;  
}G[40050];  
int n,p,ans=0;  
int h[550],q[40050],d[550];  
bool mark[550];
char s[201];
int cnt1[201],cnt[201][27],lim[201];
int Min(int a,int b){return a<b?a:b;}  
void ae(int s,int e,int c,int w){  
    G[++p]=(edge){e,c,p+1,h[s],w};h[s]=p;  
    G[++p]=(edge){s,0,p-1,h[e],-w};h[e]=p;  
}  
bool spfa(){  
    memset(d,127/3,sizeof(d));  
    memset(mark,0,sizeof(mark));  
    d[T]=0;mark[T]=1;  
    int head=0,tail=0;  
    int inf=d[0];  
    q[tail++]=T;  
    while(head!=tail){  
        int fr=q[head++];  
        for(int i=h[fr];i;i=G[i].nx){  
            if(G[G[i].rev].cap>0&&d[G[i].to]>d[fr]+G[G[i].rev].we){  
                d[G[i].to]=d[fr]+G[G[i].rev].we;  
                if(!mark[G[i].to])mark[G[i].to]=1,q[tail++]=G[i].to;  
            }  
        }  
        mark[fr]=0;  
    }  
    return !(d[0]==inf);  
}  
int dfs(int s,int t,int f){  
    mark[s]=1;  
    if(s==t) return f;  
    int sum=0;  
    for(int i=h[s];i;i=G[i].nx){  
        if(G[i].cap>0&&!mark[G[i].to]&&d[s]-G[i].we==d[G[i].to]){  
            int d=dfs(G[i].to,t,Min(G[i].cap,f));  
            if(d)sum+=d,f-=d,G[i].cap-=d,G[G[i].rev].cap+=d;  
            if(f==0)return sum;  
        }  
    }  
    return sum;  
}  
int m__f(){  
    int sum=0;  
    while(spfa()){  
        mark[T]=1;  
        while(mark[T]){  
            memset(mark,0,sizeof(mark));
            int tmp=dfs(S,T,99999999);
            sum+=tmp*d[0];  
            ans+=tmp;
        }
    }
    return sum;
}
int main(){
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++){
        cnt1[s[i]-'a'+1]++;
    }
    for(int i=1;i<=26;i++){
      if(cnt1[i]) ae(S,i,cnt1[i],0);
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
      scanf("%s%d",s,&lim[i]);
      for(int j=0;j<strlen(s);j++){
          cnt[i][s[j]-'a'+1]++;
      }
    }
    for(int i=1;i<=n;i++){
      for(int j=1;j<=26;j++){
          if(cnt[i][j]) ae(j,i+26,cnt[i][j],i);
      }
      ae(i+26,T,lim[i],0);
    }
    int cos=m__f();
    if(ans!=len) puts("-1");
    else printf("%d\n",cos);
    return 0;
}

 

posted on 2017-08-24 18:30  nzher  阅读(232)  评论(0编辑  收藏  举报