• [日常摸鱼]pojKaka's Matrix Travels-拆点+最大费最大流


    方格取数的升级版,每个格子最多取一次。

    $k=1$的话就是个普及组的dp题,$k=2$就是在之前的基础上多加两维。

    然而现在$k$太大了当然就不dp啦

    对于$k=1$的情况我们还可以把$(i,j)$向$(i+1,j),(i,j+1)$连边然后答案就是跑最长路,而对于更大的情况我们的瓶颈在于直接跑最长路不能限制每个点只取一次。

    对于点来说没有什么好的方法我们就把问题转移到边上:把每个点拆成一条边。具体的说就是把一个点拆成两个点,把点权变成边权,而我们又要限制这样子的每条边最多走一次,这里就有点费用流的感觉了(雾)。

    所以我们可以这样建图:把点$i$拆成$i$和$i'$,不妨令$i$为入点$i'$为出点,从入点到出点连两条边:一条容量为1,费用为点权$c$,另一条容量为$k-1$,费用为0。

    原图里的点的出点再向能够直接到达的点的入点连一条容量为$k$,费用为0的边。

    这样每次bfs的时候只要成功都会走出一条完整的路径,路径上的费用被算进去之后这条路也就不会再走了(因为有费用的只有容量为1的嘛),于是也就保证了只会取一次并且一定是第一次经过的时候被取走。

    以起点的入点为源点,以终点的出点为汇点跑最大费用最大流得到的就是答案啦

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define rep(i,n) for(register int i=1;i<=n;i++)
    #define REP(i,a,b) for(reigster int i=a;i<=b;i++)
    using namespace std;
    const int N=5005;
    const int M=20005;
    const int INF=(~0u>>1);
    struct edge
    {
        int to,nxt,w,c;
        edge(int to=0,int nxt=0,int w=0,int c=0):to(to),nxt(nxt),w(w),c(c){}
    }edges[M<<1];
    int n,k,s,t,ans,cnt;
    int head[M<<1],infc[N],vis[N],d[N],pre[N];
    queue<int>q;
    
    inline void addEdge(int u,int v,int w,int c)
    {
        edges[++cnt]=edge(v,head[u],w,c);head[u]=cnt;
        edges[++cnt]=edge(u,head[v],0,-c);head[v]=cnt;
    }
    inline int get_num(int i,int j,int p)
    {
        return (i-1)*n+j+n*n*p;
    }
    #define cur edges[i].to
    inline bool spfa()
    {
        memset(vis,0,sizeof vis);
        rep(i,t)d[i]=-INF;q.push(s);
        d[s]=0;infc[s]=INF;vis[s]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();vis[x]=0;
            for(register int i=head[x];i;i=edges[i].nxt)if(edges[i].w&&d[cur]<d[x]+edges[i].c)
            {
                d[cur]=d[x]+edges[i].c;
                pre[cur]=i;infc[cur]=min(infc[x],edges[i].w);
                if(!vis[cur])vis[cur]=1,q.push(cur);
            }
        }
        if(d[t]==-INF)return 0;
        return 1;
    }
    #undef cur
    inline void updata()
    {
        
        int tmp=t;
        while(tmp!=s)
        {
            int i=pre[tmp];
            edges[i].w-=infc[t];
            edges[i^1].w+=infc[t];
            tmp=edges[i^1].to;
        }
        ans+=d[t];
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        s=1;t=2*n*n;cnt=1;
        rep(i,n)rep(j,n)
        {
            int x;scanf("%d",&x);
            addEdge(get_num(i,j,0),get_num(i,j,1),1,x);
            addEdge(get_num(i,j,0),get_num(i,j,1),k-1,0);
            if(i<n)addEdge(get_num(i,j,1),get_num(i+1,j,0),k,0);
            if(j<n)addEdge(get_num(i,j,1),get_num(i,j+1,0),k,0);
        }
        while(spfa())updata();
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    The constructors Integer(int), Double(double), Long(long) and so on are deprecated
    mysql Binlog二进制日志三种模式的日志格式介绍及区别
    MySQL错误“Specified key was too long; max key length is 1000 bytes”的解决办法
    mysql 的 bin 和 .log 日志文件会非常占用磁盘空间和 IO,修改 mysql 配置文件可以关闭这两种日志的记录。
    mysql关闭binlog日志
    MySQL实现排名并查询指定用户排名功能,并列排名功能
    ROSE框架中SQL批量操作使用
    tomcat 9.0 Tomcat NOTE: Picked up JDK_JAVA_OPTIONS: addopens=java.base/java.lang=ALLUNNAMED
    浅析Spring自定义注解+aop实现对实体类的字段进行校验
    浅析redis setIfAbsent的用法及在分布式锁上的应用及同步锁的缺陷
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/8423772.html
Copyright © 2020-2023  润新知