神仙题,想了两节ds课没想出来,跑到奇怪的犄角旮旯去了还是没法搞一个满意的模型

看了洛谷黑题啊..释然了

思路和细节在代码

// LUOGU_RID: 90857083
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
using namespace std;
const int maxn=100010;

bool vis[maxn];
int n,m,k,s,t,x,y,z,f,Pre[maxn],book[maxn],a[maxn],c[maxn],dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,mincost;
//dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量 
struct Edge{
    int to,next,flow,dis;//flow流量 dis花费 
}edge[maxn];
int head[maxn],num_edge; 
queue <int> q;


void add_edge(int from,int to,int flow,int dis)
{
    edge[++num_edge].next=head[from];edge[num_edge].to=to;edge[num_edge].flow=flow;edge[num_edge].dis=dis;head[from]=num_edge;
    // 反向边流量为0,费用为负数
    edge[++num_edge].next=head[to];edge[num_edge].to=from;edge[num_edge].flow=0;edge[num_edge].dis=-dis;head[to]=num_edge;
}

bool spfa(int s,int t)
{
    memset(dis,0x7f,sizeof(dis));
    memset(flow,0x7f,sizeof(flow));
    memset(vis,0,sizeof(vis));
    q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1;
    
    while (!q.empty())
    {
        int now=q.front();
        q.pop();
        vis[now]=0;
        for (int i=head[now]; i!=-1; i=edge[i].next)
        {
            if (edge[i].flow>0 && dis[edge[i].to]>dis[now]+edge[i].dis)//正边 
            {
                dis[edge[i].to]=dis[now]+edge[i].dis;
                pre[edge[i].to]=now;
                last[edge[i].to]=i;
                flow[edge[i].to]=min(flow[now],edge[i].flow);//
                if (!vis[edge[i].to])
                {
                    vis[edge[i].to]=1;
                    q.push(edge[i].to);
                }
            }
        }
    }
    return pre[t]!=-1;
}

void MCMF()
{
    while (spfa(s,t))
    {
        int now=t;
        maxflow+=flow[t];
        mincost+=flow[t]*dis[t];
        while (now!=s)
        {//从源点一直回溯到汇点 
            edge[last[now]].flow-=flow[t];//flow和dis容易搞混 
            edge[last[now]^1].flow+=flow[t];
            now=pre[now];
        }
    }
}

int main()
{
    //freopen("lys.in","r",stdin);
    memset(head,-1,sizeof(head)); num_edge=-1;//初始化 
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>c[i];
    
    s=0;t=2*n+1;
    for(int i=1;i<=n;i++){
        /*
         拆点,对每一天拆成in 和 out
         流量为1,费用为c[i]表示当天的书必买 
         这样就能起码保证一种方案,就是说最大流就可以保证了。
         因为要决策每一天买不买不好表示,emmm也不是不行但可能
         需要用很复杂的状态表示,活生生做成dp&flow是吧
         考虑补集最近真的见到很多次了,我也该记住了,哪怕再笨
         考虑先把所有都买了——然后考虑是否有方案能够减少花费 
        */
        add_edge(s,i,1,c[a[i]]);
        /*
        in -> out,表示当天就把这本书丢了or卖了 
        */
        add_edge(i,i+n,1,0);// 流量限制为1表示丢了or卖了,only one choice 
        add_edge(i+n,t,1,0);//丢了 
        /*
          表示当天买的这本书在下一次需要的前一天给卖了,
          这样第二天买入的时候等价于-c+c,mean while we save us; 
        */
        if(Pre[a[i]]) add_edge(i-1,Pre[a[i]]+n,1,-c[a[i]]);
        Pre[a[i]]=i;
        // 这玩意要边走边维护,刚才煞笔了唔 
        /*
         为了限制流量,当天流向下一天的为k-1本,还有一个位置留给第二天强制买
         咋保留?就上面辣个先卖了,再买, 
        */
        if(i!=n) add_edge(i,i+1,k-1,0);
    }
    MCMF();
    cout<<mincost;
    return 0;
}

 

原文地址:http://www.cnblogs.com/liyishui2003/p/16814721.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性