Problem Description
You desperately need to build some string t. For that you've got n more strings s1, s2, ..., sn. To build string t, you are allowed to perform exactly |t| (|t| is the length of string t) operations on these strings. Each operation looks like that:
- choose any non-empty string from strings s1, s2, ..., sn;
- choose an arbitrary character from the chosen string and write it on a piece of paper;
- remove the chosen character from the chosen string.
Note that after you perform the described operation, the total number of characters in strings s1, s2, ..., sn decreases by 1. We are assumed to build string t, if the characters, written on the piece of paper, in the order of performed operations form string t.
There are other limitations, though. For each string si you know number ai — the maximum number of characters you are allowed to delete from string si. You also know that each operation that results in deleting a character from string si, costs i rubles. That is, an operation on string s1 is the cheapest (it costs 1 ruble), and the operation on string sn is the most expensive one (it costs n rubles).
Your task is to count the minimum amount of money (in rubles) you will need to build string t by the given rules. Consider the cost of building string t to be the sum of prices of the operations you use.
Input
The first line of the input contains string t — the string that you need to build.
The second line contains a single integer n (1 ≤ n ≤ 100) — the number of strings to which you are allowed to apply the described operation. Each of the next n lines contains a string and an integer. The i-th line contains space-separated string si and integer ai (0 ≤ ai ≤ 100). Number ai represents the maximum number of characters that can be deleted from string si.
All strings in the input only consist of lowercase English letters. All strings are non-empty. The lengths of all strings do not exceed 100 characters.
Output
Print a single number — the minimum money (in rubles) you need in order to build string t. If there is no solution, print -1.
Examples
Input
bbaze
3
bzb 2
aeb 3
ba 10Output
8
Input
abacaba
4
aba 2
bcc 1
caa 2
bbb 5Output
18
Input
xyz
4
axx 8
za 1
efg 4
t 1Output
-1
题意:给出一个字符串 str,然后有 n 个可供使用的字符串,现在在 n 个可用字符串中选取一定的字符组成字符串 str,从第 i 个串中拿一个字符的代价是 i 且最多拿 num[i] 个,求组成目标字符串的最小花费
思路:最小费用流
设置一个超级源点与超级汇点,从源点到 26 个字符建边,容量记为字符串 str 的个数,费用为 0,然后将每个字符向 n 个字符串建边,对于第 i 个串来说,容量为该串中相应字符的个数,费用为 i,最后对每个模式串向汇点建边,容量为 num[i],费用为 0
最后如果出现满流,则说明可以构造出 str 串
Source Program
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 10000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
struct Edge{
int from,to;
int cap,flow;
int cost;
int next;
}edge[N];
int head[N],tot;
char str[N];
int bucket[27];//str串中字符个数
int G[N][27];//n个字符串每串的字符个数
int num[N];//n个字符串每串最多取的个数
int pre[N];//记录从S到i的最小费用路径上的最后一条弧编号
int dis[N];
bool vis[N];
bool SPFA(int S,int T) {
queue<int> Q;
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(pre,-1,sizeof(pre));
dis[S]=0;
Q.push(S);
while(!Q.empty()) {
int x=Q.front();
Q.pop();
vis[x]=false;
for(int i=head[x];i!=-1;i=edge[i].next) {
int y=edge[i].to;
int cost=edge[i].cost;
int cap=edge[i].cap;
int flow=edge[i].flow;
if(dis[y]>dis[x]+cost&&cap>flow) {
dis[y]=dis[x]+cost;
pre[y]=i;
if(!vis[y]){
vis[y]=true;
Q.push(y);
}
}
}
}
return pre[T]!=-1;
}
void MCMF(int S,int T,int &flow,int &cost){
flow=0;
cost=0;
while(SPFA(S,T)){//每次寻找花销最小的路径
int minn=INF;
for(int i=pre[T];i!=-1;i=pre[edge[i^1].to])//寻找最小增广流
minn=min(minn,edge[i].cap-edge[i].flow);
for(int i=pre[T];i!=-1;i=pre[edge[i^1].to]) {
edge[i].flow+=minn;
edge[i^1].flow-=minn;
cost+=edge[i].cost*minn;//增广流的花销
}
flow+=minn;//总流量增加
}
}
void addEdge(int from,int to,int cap,int flow,int cost){
edge[tot].from=from;
edge[tot].to=to;
edge[tot].cap=cap;
edge[tot].flow=flow;
edge[tot].cost=cost;
edge[tot].next=head[from];
head[from]=tot++;
}
int main(){
scanf("%s",str);
int len=strlen(str);
for(int i=0;i<len;i++)//统计str串中字符的个数
bucket[str[i]-'a'+1]++;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
char temp[N];
scanf("%s%d",temp,&num[i]);
int length=strlen(temp);
for(int j=0;j<length;j++)
G[i][temp[j]-'a'+1]++;//统计第i个字符串中字符的个数
}
tot=0;
memset(head,-1,sizeof(head));
int S=0,T=26+n+1;
for(int i=1;i<=26;i++){
if(bucket[i]==0)
continue;
//源点到26个字符
addEdge(S,i,bucket[i],0,0);//正向边
addEdge(i,S,0,0,0);//反向边
for(int j=1;j<=n;j++){
if(G[j][i]==0)
continue;
//26个字符到n个字符串
addEdge(i,26+j,G[j][i],0,j);//正向边
addEdge(26+j,i,0,0,-j);//反向边
}
}
for(int i=1;i<=n;i++){//n个字符串到汇点
addEdge(26+i,T,num[i],0,0);//正向边
addEdge(T,26+i,0,0,0);//反向边
}
int flow,cost;
MCMF(S,T,flow,cost);
if(flow!=len)//不满流
printf("-1\n");
else//满流
printf("%d\n",cost);
return 0;
}