天天看點

jzoj 4020. 【雅禮聯考DAY02】Revolution 最小割

Description

地圖是個矩形的網格。

可以花費一定金錢在一些格子投資。

被投資的格子或者四連通的格子都被投資的話,我就可以獲得該格子的收益。

利益最大化是作為商人的基本準則,但這是計算機的任務,拜托您了。

Input

第一行兩個數 n,m(n,m ≤ 20),表示矩形的長和寬。

接下來 n 行,每行是 m 個字元組成的字元串,描述投資的花費。

接下來 n 行,每行是 m 個字元組成的字元串,表示該格子的收益。

花費和收益按照一種奇葩的方式給出:

字元 數

‘0’ -’ 9’ 0-9

‘a’ -’ z’ 10-35

‘A’ -’ Z’ 36-61

Output

一個數,表示收益的和減去投資的和的最大值。

Sample Input

【樣例 1】

2 2

21

12

21

12

【樣例 2】

2 2

ZZ

ZZ

11

11

【樣例 3】

3 3

XXX

XXX

XXX

aaa

aZa

aaa

【樣例 4】

2 4

asam

atik

123A

45BC

【樣例 5】

9 8

IIIIIIII

IIWWWWII

IIWIIIII

IIWIIIII

IIWWWWII

IIIIIWII

IIIIIWII

IIWWWWII

IIIIIIII

IIIIIIII

II0000II

II0II0II

II0II0II

II0000II

II0II0II

II0II0II

II0000II

IIIIIIII

Data Constraint

n,m ≤ 20.

分析:

一看到這一題,好像文理分科啊,然後按着這個想法推了一下。

首先一塊地可以選和不選,選了要花錢,不選就拿不到這塊地的價值。是以我們考慮把所有價值加起來,然後用最小割解決。

建圖模型,大概是這樣的,沒寫權值的邊為 INF I N F

jzoj 4020. 【雅禮聯考DAY02】Revolution 最小割

首先一個拆成三個點,然後第一個點向第二個點連一條 costi c o s t i 的邊,第二個點向第三個點連一條 valuei v a l u e i 的邊,這兩條邊要斷掉一個,即選或不選。如果切掉 costi c o s t i 的邊,則說明我們買了該點,要減去買的費用;否則為不買,因為我們一開始 ans a n s 是所有價值的和,是以要減去。

還有一種方法可以得到這個權值,那就是把周圍的點全部買下來,周圍的點記為 j j ,即把costjcostj全部割掉,也就是上圖左邊的三條邊;如果有一個 j j 割的是valuejvaluej的邊,就是有一個不買,都要割掉 valuei v a l u e i 的邊。肯定不可能 valuej v a l u e j 和 costj c o s t j 同時割掉,這樣就血虧了,而且也不可能。

然後我們給這個棋盤黑白染色,黑點在一邊,白點在一邊,然後跑最大流就可以了。

好像拆成兩個點也可以,不過資料範圍很小。

一開始想法是把 costi c o s t i 放一邊, valuei v a l u e i 放另外一邊,怎麼想都做不出來= =

代碼:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>

const int inf=;

using namespace std;

int n,m,cnt,s,t,ans;
int cost[][],value[][];
int dis[],ls[];

queue <int> q;

struct edge{
    int y,c,op,next;
}g[];

int calc(char ch)
{
    if ((ch>='0') && (ch<='9')) return (ch-'0');
    if ((ch>='a') && (ch<='z')) return (ch-'a'+);
    return (ch-'A'+);
}

void init()
{
    char s[],ch;
    scanf("%d%d",&n,&m);
    for (int i=;i<=n;i++)
    {
        scanf("%s",s);
        scanf("%c",ch);
        for (int j=;j<=m;j++)
        {
            cost[i][j]=calc(s[j-]);
        }
    }
    for (int i=;i<=n;i++)
    {
        scanf("%s",s);
        scanf("%c",ch);
        for (int j=;j<=m;j++)
        {
            value[i][j]=calc(s[j-]);
            ans+=value[i][j];
        }
    }
}

void add(int x,int y,int w)
{
    g[++cnt]=(edge){y,w,cnt+,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,,cnt-,ls[y]};
    ls[y]=cnt;
}

int op(int x,int y)
{
    return (x-)*m+y-;
}

bool bfs()
{
    for (int i=s;i<=t;i++) dis[i]=;
    dis[s]=;
    while (!q.empty()) q.pop();
    q.push(s);
    while (!q.empty())
    {
        int u=q.front();
        q.pop();
        for (int i=ls[u];i>;i=g[i].next)
        {
            int v=g[i].y;
            if ((dis[v]==) && (g[i].c))
            {
                dis[v]=dis[u]+;
                if (v==t) return true;
                q.push(v);
            }
        }
    }
    return false;
}

int dfs(int x,int maxf)
{
    if ((x==t) || (maxf==)) return maxf;
    int ret=;
    for (int i=ls[x];i>;i=g[i].next)
    {
        int y=g[i].y;
        if ((dis[x]+==dis[y]) && (g[i].c))
        {
            int f=dfs(y,min(maxf-ret,g[i].c));
            g[i].c-=f;
            g[g[i].op].c+=f;
            ret+=f;
        }
    }
    return ret;
}

int main()
{
    init();
    s=; t=n*m*3+; 
    for (int i=;i<=n;i++)
    {
        for (int j=;j<=m;j++)
        {
            if ((i+j)%2==)
            {
                int x=op(i,j);
                add(s,x*3+,inf);
                add(x*3+,x*3+,cost[i][j]);
                add(x*3+,x*3+,value[i][j]);
                if (i>) 
                {
                    int y=op(i-,j);
                    add(x*3+,y*3+,inf);
                    add(x*3+,y*3+,inf);
                }
                if (i<n)
                {
                    int y=op(i+,j);
                    add(x*3+,y*3+,inf);
                    add(x*3+,y*3+,inf);
                }
                if (j>)
                {
                    int y=op(i,j-);
                    add(x*3+,y*3+,inf);
                    add(x*3+,y*3+,inf);
                }
                if (j<m)
                {
                    int y=op(i,j+);
                    add(x*3+,y*3+,inf);
                    add(x*3+,y*3+,inf);
                }

            }
            else
            {
                int x=op(i,j);
                add(x*3+,t,inf);
                add(x*3+,x*3+,cost[i][j]);
                add(x*3+,x*3+,value[i][j]);
            }
        }
    }
    while (bfs()) ans-=dfs(s,inf);
    printf("%d",ans);
}