• CF237E Build String(最小费用最大流)


    题目大意:

    你需要使用一些字符串s_1s1s_2s2,......,s_nsn来构建字符串t,你可以执行|t|t∣ (|t|t∣是字符串t的长度)次操作:

    1. 从字符串s_1s1s_2s2,......,s_nsn中选择一个非空字符串;
    2. 从所选字符串中选择一个字符并将其写在纸上;
    3. 从所选字符串中删除所选字符。

    注意:执行上述操作后,字符串s_1s1s_2s2,......,s_nsn中的字符总数减少1。

    我们认为构建出了字符串t,当且仅当写在纸上的字符按顺序连起来为t。

    但是还有其他限制:对于每个字符串s_isi,有a_iai为允许从字符串s_isi中删除的最大字符数。

    而且,从字符串s_isi中每个删除字符的操作都需要一些代价。对于s_isi,从中删除1个字符需要花费i的代价。

    你的任务是计算根据给定规则构建字符串t所需的最小代价。

    输入格式

    输入的第一行包含字符串t。

    第二行包含一个整数n。

    接下来的n行,每一行都包含一个字符串s_isi和一个整数a_iai(使用空格隔开),含义如题目所述。

    输出格式

    输出一个数字,为最小代价。若无解,请输出-1。

    题解:

    经典最小费用最大流,建图方法在注释里,最小费用最大流还是要更加熟练,在cf那种高压的状态下没有时间调试的。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    const int inf=1e9;
    string S[maxn];
    string T;
    int w[maxn];
    int num[26];//目标串中每个数出现的次数 
    int c[26][maxn];//每个串中数字出现的次数
    int n;
    int s,t;
    int visit[maxn];
    int dis[maxn];//源点到每个点的最小花费(最短路)
    int pre[maxn];//前驱
    int lst[maxn];//每个点所连的前一条边
    int flow[maxn];//源点到此处的流量
    int maxflow;//最大流
    int mincost;//最小费用
    struct node {
        int u,v,flow,dis,nxt;
    }edge[maxn*2];
    int tot;
    int head[maxn];
    void addedge (int u,int v,int flow,int dis) {
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].flow=flow;
        edge[tot].dis=dis;
        edge[tot].nxt=head[u];
        head[u]=tot++;
        
        
        edge[tot].u=v;
        edge[tot].v=u;
        edge[tot].flow=0;
        edge[tot].dis=-dis;
        edge[tot].nxt=head[v];
        head[v]=tot++;
    } 
    bool spfa (int s,int t) {
        for (int i=0;i<maxn;i++) dis[i]=inf,flow[i]=inf,visit[i]=0;
        queue<int> q;
        q.push(s);
        visit[s]=1;
        dis[s]=0;
        pre[t]=-1;
        while (!q.empty()) {
            int u=q.front();
            q.pop();
            visit[u]=0;
            for (int i=head[u];i!=-1;i=edge[i].nxt) {
                if (edge[i].flow>0&&dis[edge[i].v]>dis[u]+edge[i].dis) {
                    dis[edge[i].v]=dis[u]+edge[i].dis;
                    pre[edge[i].v]=u;
                    lst[edge[i].v]=i;
                    flow[edge[i].v]=min(flow[u],edge[i].flow);
                    if (!visit[edge[i].v]) {
                        visit[edge[i].v]=1;
                        q.push(edge[i].v);
                    }
                }
            }
        }
        return pre[t]!=-1;
    } 
    void MCMF () {
        while (spfa(s,t)) {
            int u=t;
            maxflow+=flow[t];
            mincost+=flow[t]*dis[t];
            while (u!=s) {
                edge[lst[u]].flow-=flow[t];
                edge[lst[u]^1].flow+=flow[t];
                u=pre[u];
            }
        }
    } 
    
    int main () {
        //最小费用最大流
        //0为源点
        //1~26为每个字母代表的点
        //26+1~26+n为每个串代表的点
        
        //27+n为汇点 
        
        //源点向每个字母连一条容量为num[i],费用为0的边
        //每个字母i向每个串j连一条容量为c[i-1][j],费用为j的边
        //每个串i向汇点连一条容量为串的最大删除数,费用为0的边 
        memset(head,-1,sizeof(head));
        cin>>T;
        scanf("%d",&n);
        s=0;
        t=27+n;
        for (int i=1;i<=n;i++) cin>>S[i]>>w[i];
        for (int i=1;i<=n;i++) {
            for (int j=0;j<S[i].length();j++)
                c[S[i][j]-'a'][i]++;
        }
        for (int i=0;i<T.length();i++)
            num[T[i]-'a']++;
        for (int i=1;i<=26;i++)
            addedge(s,i,num[i-1],0);
        for (int i=1;i<=26;i++) {
            for (int j=1;j<=n;j++) {
                addedge(i,26+j,c[i-1][j],j);
            }
        }
        for (int i=1;i<=n;i++)
            addedge(26+i,t,w[i],0);
        MCMF();
        if (maxflow!=T.length()) return printf("-1"),0;
        printf("%d
    ",mincost);
    }
  • 相关阅读:
    vue苦逼自学之路
    第一次博客作业
    u3d学习资料
    leetcode——Divide Two Integers
    leetcode——Swap Nodes in Pairs
    leetcode——Merge k Sorted Lists
    leetcode——Container With Most Water
    leetcode——Regular Expression Matching
    leetcode——Longest Palindromic Substring
    CC_CALLBACK之间的区别
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13510200.html
Copyright © 2020-2023  润新知