• 王者之剑


    这是在阿尔托利亚·潘德拉贡成为英灵前的事情,她正要去拔出石中剑成为亚瑟王,在这之前她要去收集一些宝石。

    宝石排列在一个n*m的网格中,每个网格中有一块价值为v(i,j)的宝石,阿尔托利亚·潘德拉贡可以选择自己的起点。

    开始时刻为0秒。以下操作,每秒按顺序执行

    1.在第i秒开始的时候,阿尔托利亚·潘德拉贡在方格(x,y)上,她可以拿走(x,y)中的宝石。

    2.在偶数秒,阿尔托利亚·潘德拉贡周围四格的宝石会消失

    3.若阿尔托利亚·潘德拉贡第i秒开始时在方格(x,y)上,则在第i+1秒可以立即移动到(x+1,y),(x,y+1),(x-1,y)或(x,y-1)上,也可以停留在(x,y)上。

    求阿尔托利亚·潘德拉贡最多可以获得多少价值的宝石

    【输入格式】

    第一行给出数字N,M代表行列数.N,M均小于等于100,宝石的价值不会超过10000.下面N行M列用于描述数字矩阵

    【输出格式】

    输出最多可以拿到多少价值宝石

    【样例输入】

    2 2

    1 2

    2 1

    【样例输出】

    4

    【题解】
    论黑白点染色是怎样一个常用套路……因为每个点和它周围一圈的四个点一定不能同时拿到,而且只有偶数时刻可以取数,所以把不相容的点之间建一条权值极大的边。每个黑点和源点、白点和汇点之间的边权值为这个点的价值。对于白点来说汇点的意义是选、源点是不选,对于黑点正相反,这就是翻转源汇的思想。最小割中割掉的边是被舍弃的边,用刚开始矩阵的总权值减去割的权值即可。注意即使建极大值的边也是正向极大反向为0,否则可能会出现很多不可知的错误。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int sj=105;
    int n,m,vl[sj][sj],h[sj*sj],e,s,t,sx[sj][sj],jg,dep[sj*sj],ma;
    bool hb[sj][sj];
    struct B
    {
         int ne,v,w;
    }b[sj*sj*10];
    void add(int x,int y,int z)
    {
         b[e].v=y;
         b[e].w=z;
         b[e].ne=h[x];
         h[x]=e++;
    }
    int bj(int x,int y)
    {
        return x<y?x:y;
    }
    void init()
    {
         scanf("%d%d",&n,&m);
         memset(h,-1,sizeof(h));
         s=0;
         t=n*m+1;
         ma=1000010;
         for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
           { 
             scanf("%d",&vl[i][j]);
             if((i&1)==(j&1)) hb[i][j]=1;
             jg+=vl[i][j];
             sx[i][j]=m*(i-1)+j;
           }
         for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
           {
             if(hb[i][j]) 
             {
               add(s,sx[i][j],vl[i][j]),add(sx[i][j],s,0);
               if(i-1)
                 add(sx[i][j],sx[i-1][j],ma),add(sx[i-1][j],sx[i][j],0);
               if(j-1)
                 add(sx[i][j],sx[i][j-1],ma),add(sx[i][j-1],sx[i][j],0);
               if(i+1<=n)
                 add(sx[i][j],sx[i+1][j],ma),add(sx[i+1][j],sx[i][j],0);
               if(j+1<=m)
                 add(sx[i][j],sx[i][j+1],ma),add(sx[i][j+1],sx[i][j],0);     
             }
             if(!hb[i][j])
               add(sx[i][j],t,vl[i][j]),add(t,sx[i][j],0);
           }
    }
    queue<int> q;
    bool bfs(int x)
    {
        memset(dep,0,sizeof(dep));
        dep[x]=1;
        while(!q.empty()) q.pop();
        q.push(x);
        while(!q.empty())
        {
           x=q.front();
           q.pop();
           for(int i=h[x];i!=-1;i=b[i].ne)
             if(b[i].w&&!dep[b[i].v])
             {
                dep[b[i].v]=dep[x]+1;
                if(b[i].v==t) return 1;
                q.push(b[i].v);
             }
        }
        return 0;
    }
    int dfs(int x,int f)
    {
        int ans=0;
        if(x==t) return f;
        for(int i=h[x],d;i!=-1;i=b[i].ne)
          if(b[i].w&&dep[b[i].v]>dep[x])
          {
             d=dfs(b[i].v,bj(b[i].w,f));
             f-=d;
             ans+=d;
             b[i].w-=d;
             b[i^1].w+=d;
          }
        if(!ans) dep[x]=-1;
        return ans;
    }
    int main()
    {
        //freopen("t.txt","r",stdin);
        freopen("Excalibur.in","r",stdin);
        freopen("Excalibur.out","w",stdout);
        init();
        while(bfs(s)) jg-=dfs(s,ma*100);
        printf("%d",jg);
        //while(1);
        return 0;
    }
    Excalibur
     
  • 相关阅读:
    Android系统架构概述
    过滤IE浏览器版本
    gearman入门使用
    MYSQL中利用select查询某字段中包含以逗号分隔的字符串的记录方法
    PHP操作Excel – PHPExcel 基本用法详解
    java中怎么判断一个字符串是否存在数组中
    为java程序制作exe
    jsonp的原理
    mysql的联合查询
    移动开发---页面头部信息
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7261198.html
Copyright © 2020-2023  润新知