zoukankan      html  css  js  c++  java
  • POJ 3422 Kaka's Matrix Travels

    题目链接:ヾ(≧∇≦*)ゝ

    大致题意:给你一个(n*n)的矩阵从((1,1))出发,到((n,n))结束,只能走右边或左边。每个点在被走过之后权值变成0,问走(k)次后,能获得的最大值总和是多少

    Solution:

    看数据范围,(nle50,0le k le10),再结合题目,一下子就能想到费用流

    那么,该如何建图呢?

    我们看一下限制:

    首先,每一个点只能贡献一次价值,如何来解决这个问题呢?

    拆点。把每个点分为入点和出点,入点和出点之间的费用为该点权值,容量为1,这样就能够解决这条限制。

    然后,再把每一个点的出点与它右边的点的入点和下面的点的入点连边,费用为0,容量为k

    再是能够走k次,我们建立一个超级源点和超级汇点,拿出发点的入点与源点连边,容量为k,费用为0,结束点的出点与汇点连边,容量为k,费用为0

    不过,仅仅这样是不行的。按照上述的建图,我们发现它只能应对(kle2)的情况,最多跑完两次最大费用流,它就会无路可走,所以我们还需要连一些边。

    对于每一个点,将它的出点与它右边点的的出点,下面点的出点都连一条容量为k,费用为0的边。

    这是什么意思呢?这条边代表只是经过这个点,而不取该点的权值。

    最后跑最大费用流,拿答案减去多加的出发点和结束点的权值,就是答案了

    不过,当(k=0)时,需要特判一下,直接输出0。(博主就是因为忘记特判而狂WA不止啊...)

    Code:

    #include<queue>
    #include<cstdio>
    #include<ctype.h>
    #include<cstring>
    #include<algorithm>
    #define N 30001
    #define inf 0x8f
    using namespace std;
    int S,T,n,k,cnt=1,tot;
    int head[N],mp[51][51];
    struct Edge{int nxt,to,v,w;}edge[N];
    void ins(int x,int y,int z,int w){
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;edge[cnt].v=z;
        edge[cnt].w=w;head[x]=cnt;
    }
    namespace Network_Flow{
        queue<int> q;
        int maxcost,delta;
        int dis[N],vis[N],pre[N];
        int spfa(){
            pre[T]=0;delta=inf;
            memset(vis,0,sizeof(vis));
            memset(dis,255,sizeof(dis));
            q.push(S);vis[S]=1;dis[S]=0;
            while(!q.empty()){
                int x=q.front();q.pop();vis[x]=0;
                for(int i=head[x];i;i=edge[i].nxt){
                    int y=edge[i].to;
                    if(edge[i].v&&dis[x]+edge[i].w>dis[y]){
                        dis[y]=dis[x]+edge[i].w;
                        delta=min(delta,edge[i].v);
                        pre[y]=i;if(!vis[y]) q.push(y),vis[y]=1;
                    }
                }
            }
            return pre[T];
        }
        void update(){
            int x=T;
            while(x!=1){
                int i=pre[x];
                edge[i].v-=delta;
                edge[i^1].v+=delta;
                x=edge[i^1].to;
            }
            maxcost+=dis[T]*delta;
        }
        void Edmond_Karp(){
            while(spfa()) update();
            printf("%d
    ",maxcost-(k-1)*(mp[1][1]+mp[n][n]));
        }
    }
    int num(int i,int j){return (i-1)*n*2+j*2;}
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int main(){
        n=read(),k=read();S=n*n*2+1,T=S+1;
        using namespace Network_Flow;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                mp[i][j]=read();tot+=2;
                if((i==1&&j==1)||(i==n&&j==n)){
                    ins(tot-1,tot,k,mp[i][j]);
                    ins(tot,tot-1,0,-mp[i][j]);
                    continue;
                }
                ins(tot-1,tot,1,mp[i][j]);
                ins(tot,tot-1,0,-mp[i][j]);
            }
        if(!k){printf("0");return 0;}
        ins(S,1,inf,0);ins(1,S,0,0);
        ins(tot,T,inf,0);ins(T,tot,0,0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                if(i<n){
                    ins(num(i,j),num(i+1,j)-1,k,0);
                    ins(num(i+1,j)-1,num(i,j),0,0);
                    ins(num(i,j),num(i+1,j),k,0);
                    ins(num(i+1,j),num(i,j),0,0);
                }
                if(j<n){
                    ins(num(i,j),num(i,j+1)-1,k,0);
                    ins(num(i,j+1)-1,num(i,j),0,0);
                    ins(num(i,j),num(i,j+1),k,0);
                    ins(num(i,j+1),num(i,j),0,0);
                }
            }
        Edmond_Karp();
        return 0;
    }
    
  • 相关阅读:
    Android应用开发之避免内存泄露
    史上最经典的数据库面试题之二
    某大型银行深化系统之二十一:Log4j执行性能
    ruby支持批量数组的定义
    为VIM提供python代码提示功能
    使用win7登陆远程机器时自动保存密码
    安装Beanstalk
    在linux下安装或者卸载nginx
    python的数据类型
    使Ruby自动定位查找本地路径
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10333559.html
Copyright © 2011-2022 走看看