给 一 个 模 式 串 S 和 n 个 字 符 串 , 问 能 不 能 在 这 n 个 字 符 串 中 选 取 字 符 从 而 组 成 一 个 S 。 给一个模式串S和n个字符串,问能不能在这n个字符串中选取字符从而组成一个S。 给一个模式串S和n个字符串,问能不能在这n个字符串中选取字符从而组成一个S。
在 t i 中 取 一 个 字 符 的 费 用 为 i , 每 个 字 符 串 最 大 取 字 符 个 数 为 a i 。 在t_i中取一个字符的费用为i,每个字符串最大取字符个数为a_i。 在ti中取一个字符的费用为i,每个字符串最大取字符个数为ai。
若 能 组 成 , 则 输 出 最 小 费 用 , 否 则 输 出 − 1. 若能组成,则输出最小费用,否则输出-1. 若能组成,则输出最小费用,否则输出−1.
看 到 这 个 费 用 , 在 转 化 成 网 络 流 模 型 , 这 题 就 A 了 。 看到这个费用,在转化成网络流模型,这题就A了。 看到这个费用,在转化成网络流模型,这题就A了。
设点:
设 每 个 字 符 为 1 − 26 , n 个 串 的 为 26 + i ( i ϵ n ) 。 源 点 为 0 , 汇 点 为 n + 26 + 1 。 设每个字符为1-26,n个串的为26+i(i\epsilon n)。源点为0,汇点为n+26+1。 设每个字符为1−26,n个串的为26+i(iϵn)。源点为0,汇点为n+26+1。
建边:
跑 一 遍 M C M F , 判 断 是 否 满 流 , 即 m a x f l o w = n , 输 出 m i n c o s t , 否 则 输 出 − 1 。 跑一遍MCMF,判断是否满流,即maxflow=n,输出mincost,否则输出-1。 跑一遍MCMF,判断是否满流,即maxflow=n,输出mincost,否则输出−1。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
#define endl "\n"
#define pb push_back
#define mem(a, b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
const int INF = 0x3f3f3f3f;
// const ll mod = 998244353;
// const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
const double R = 0.57721566490153286060651209;
const int maxn = 1005; //点数
struct Edge {
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {
}
};
struct MCMF {
int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn]; //是否在队列中
int d[maxn]; //bellmanford
int p[maxn]; //上一条弧
int a[maxn]; //可改进量
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void add(int from, int to, int cap, int cost) {
edges.emplace_back(Edge(from, to, cap, 0, cost));
edges.emplace_back(Edge(to, from, 0, 0, -cost));
m = int(edges.size());
G[from].emplace_back(m - 2);
G[to].emplace_back(m - 1);
}
bool spfa(int s, int t, int &flow, int &cost) {
for (int i = 1; i <= n; ++i) d[i] = INF;
memset(inq, 0, sizeof(inq));
d[s] = 0;
inq[s] = 1;
p[s] = 0;
queue<int> q;
a[s] = INF;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = 0; i < int(G[u].size()); ++i) {
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if (!inq[e.to]) {
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if (d[t] == INF) return false;
flow += a[t];
cost += d[t] * a[t];
for (int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
return true;
}
int MincostMaxflow(int s, int t, int &cost) {
int flow = 0;
cost = 0;
while (spfa(s, t, flow, cost));
return flow;
}
} mcmf;
int n, m, mincost;
void solve() {
string S; cin >> S;
cin >> n;
map<int, int> num, mp[n + 1];
vector<int> a(n + 1);
for(int i = 0;i < S.length(); i++) {
num[S[i] - 'a' + 1]++;
}
for(int i = 1;i <= n; i++) {
string T;
cin >> T >> a[i];
for(int j = 0;j < T.length(); j++) {
mp[i][T[j] - 'a' + 1]++;
}
}
int s = 0, t = n + 26 + 1;
mcmf.init(t);
for(int i = 1;i <= 26; i++) {
if(!num[i]) continue;
mcmf.add(s, i, num[i], 0); // 源点连接每个字符,流量为S串每个字符点个数
for(int j = 1;j <= n; j++) {
if(!mp[j][i]) continue;
mcmf.add(i, j + 26, mp[j][i], j); // 每个字符连接n个字符串,流量为该字符串中i的个数,费用为行标j
}
}
for(int i = 1;i <= n; i++) {
mcmf.add(i + 26, t, a[i], 0); // 每个字符串连接汇点,流量为a[i],即最大使用次数
}
int maxflow = mcmf.MincostMaxflow(s, t, mincost);
if(maxflow == S.length()) cout << mincost << endl;
else cout << -1 << endl;
}
signed main() {
solve();
}