题意: 一个目标串和n个其他的串(编号1..n),用其他串求目标串且费用最小。 对其他串的操作:最多能从该串取K个字符,且每取一个的费用是该串的编号,取的字符从其他串删除,加到目标串中。
解法: 最小费用最大流
建图: 因为,串只含小写字母,所以,目标串化成26个字母,增加超级源点和汇点,26个字母连一条边到汇点,容量为目标 串中该字母的个数,费用为0;对于给出的n个串,统计每一个串中各个字母的个数,并与各个字母连一条边,容量为该串中字母的个数,费用为0;再连向源点一条边到该串,容量和费用都为K。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 200 ;
const int maxm = 6000 ;
const int oo = 1<<30 ;
typedef __int64 LL ;
#define clr(p,v) memset(p,v,sizeof(p))
int n,m;
struct Edge { int v,c,len,ne; }e[maxm];
int first[maxn],tot;
void init()
{
tot = 0;
clr(first,-1);
}
void add(int x,int y,int z,int c)
{
e[tot].v=y;e[tot].c=c;e[tot].len=z;e[tot].ne=first[x];first[x]=tot++;
e[tot].v=x;e[tot].c=0;e[tot].len=-z;e[tot].ne=first[y];first[y]=tot++;
}
int dis[maxn],q[maxn],top,tail,pr[maxm],L,S,T,N;
bool vis[maxn];
bool spfa()
{
for(int i=1;i<=N;i++) dis[i] = i==S?0:oo;
clr(vis,true);
top = 0; tail = 1;
q[tail] = S;
while(top != tail)
{
top = (top+1)%maxn;
int cur = q[top];
vis[cur] = true;
for(int i=first[cur];i!=-1;i=e[i].ne)
{
int vv = e[i].v;
if(e[i].c && dis[vv] > dis[cur]+e[i].len)
{
dis[vv] = dis[cur]+e[i].len;
pr[vv] = i;//
if(vis[vv])
{
vis[vv] = false;
tail = (tail+1)%maxn;
q[tail] = vv;
}
}
}
}
return (dis[T]!=oo);
}
int mcmf()
{
int flow,cost;
flow = cost = 0;
while(spfa())
{
int u = T,mi = oo;
while(u != S)
{
mi = min(mi,e[pr[u]].c);
u = e[pr[u]^1].v;
}
u = T;
flow += mi;
cost += mi*dis[T];
while(u != S)
{
e[pr[u]].c -= mi;
e[pr[u]^1].c += mi;
u = e[pr[u]^1].v;
}
}
if(flow != L) return -1;
return cost;
}
char s[110];
int va[30];
int main()
{
while(~scanf(" %s%d",s,&n))
{
init();
N = n+28;
S = N-1; T = N;
//
clr(va,0);
L = strlen(s);
for(int i=0;i<L;i++) va[s[i]-'a'+1]++;
for(int i=1;i<=26;i++) add(S,i,0,va[i]);
//for(int i=1;i<=26;i++) add(i+n,T,0,va[i]);
//
for(int i=1;i<=n;i++)
{
int k;
scanf(" %s%d",s,&k);
clr(va,0);
for(int j=0;s[j]!=0;j++) va[s[j]-'a'+1]++;
for(int j=1;j<=26;j++) add(j,i+26,0,va[j]);
add(i+26,T,i,k);
//for(int j=1;j<=26;j++) add(i,j+n,0,va[j]);
//add(S,i,i,k);
}
printf("%d\n",mcmf());
}
return 0;
}