• begin.BZOJ 1383: 三取方格数


    题目链接:传送门

    题目大意:给你一个矩阵,每个格子有一个值,现在你要从左上角走到右下角(走3次),使得经过路径的权值和最大。

         每个格子的值只能取一次,取完后变为0,输出走完三次后最大的权值和。

    题目思路:费用流做法,对于每个格子拆点,因为权值只有第一次能取,所以将每个格子拆为两条边,一条边容量为1,费用为格子的权值,另一条边容量2,费用0。

           相邻格子间连边,容量3,费用0。再建立源点S 与左上角第一个格子连边容量3,费用0。汇点 T 与右下角最后一个格子连边,容量3,费用0。跑费用流累加费用即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <stack>
    #include <cctype>
    #include <queue>
    #include <string>
    #include <vector>
    #include<functional>
    #include <set>
    #include <map>
    #include <climits>
    #define lson root<<1,l,mid
    #define rson root<<1|1,mid+1,r
    #define fi first
    #define se second
    #define ping(x,y) ((x-y)*(x-y))
    #define mst(x,y) memset(x,y,sizeof(x))
    #define mcp(x,y) memcpy(x,y,sizeof(y))
    using namespace std;
    #define gamma 0.5772156649015328606065120
    #define MOD 1000000007
    #define inf 0x3f3f3f3f
    #define N 100005
    #define maxn 10005
    typedef pair<int,int> PII;
    typedef long long LL;
     
    int n,m,ans,S,T,cost;
    char pic[55][55];
    int num[55][55];
    int vis[maxn],pre[maxn],d[maxn];
    struct Node{
        int to,next,f,c;
        Node(){}
        Node(int a,int b,int _c,int d):to(a),next(b),f(_c),c(d){}
    }node[N];int head[maxn],hcnt;
    queue<int>q;
    inline void add(int x,int y,int f,int c){
        node[hcnt]=Node(y,head[x],f,c);head[x]=hcnt++;
        node[hcnt]=Node(x,head[y],0,-c);head[y]=hcnt++;
    }
    void init(){
        mst(head,-1);hcnt=0;
        S=0;T=n*n*2+1;
        add(S,1,3,0);add(num[n][n]+n*n,T,3,0);
        for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
            if(i+1<=n)add(num[i][j]+n*n,num[i+1][j],3,0);
            if(j+1<=n)add(num[i][j]+n*n,num[i][j+1],3,0);
            add(num[i][j],num[i][j]+n*n,2,0);
            add(num[i][j],num[i][j]+n*n,1,pic[i][j]-'0');
        }
    }
    int spfa(){
        pre[S]=pre[T]=-1;
        mst(vis,0);mst(d,-1);d[S]=0;
        q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            vis[x]=0;
            for(int i=head[x];~i;i=node[i].next){
                int e=node[i].to;
                if(node[i].f&&d[e]<d[x]+node[i].c){
                    pre[e]=i^1;
                    d[e]=d[x]+node[i].c;
                    if(!vis[e]){
                        q.push(e);
                        vis[e]=1;
                    }
                }
            }
        }
        return pre[T]!=-1;
    }
    void mcmf(){
        init();
        while(spfa()){
            int fl=inf;
            for(int i=pre[T];~i;i=pre[node[i].to])
                fl=min(fl,node[i^1].f);
            for(int i=pre[T];~i;i=pre[node[i].to]){
                node[i].f+=fl;node[i^1].f-=fl;
            }
            cost+=d[T];
        }
        printf("%d
    ",cost);
    }
    int main() {
        int i,j,group,x,y,Case=0;
        scanf("%d",&n);
        for(i=1;i<=n;++i){
            scanf("%s",pic[i]+1);
            for(j=1;j<=n;++j)
                num[i][j]=++Case;
        }
        mcmf();
        return 0;
    }

         

  • 相关阅读:
    [hdu3853]LOOPS(概率dp)
    [poj2096]Collecting Bugs(概率dp)
    lintcode-42-最大子数组 II
    lintcode-39-恢复旋转排序数组
    lintcode-36-翻转链表 II
    lintcode-34-N皇后问题 II
    lintcode-33-N皇后问题
    lintcode-32-最小子串覆盖
    lintcode-31-数组划分
    lintcode-30-插入区间
  • 原文地址:https://www.cnblogs.com/Kurokey/p/5726902.html
Copyright © 2020-2023  润新知