[COGS 2051] 王者之剑 题解 网络流最大权闭合子图

【题目描述】

saber
这是在阿尔托利亚·潘德拉贡成为英灵前的事情,她正要去拔出石中剑成为亚瑟王,在这之前她要去收集一些宝石。
宝石排列在一个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

与网络流24题中方格取数相同
最大权闭合子图
黑白染色
相邻连INF的边
源点向白格子连格子权值的边
黑格子想汇点连权值的边

跑一遍最小割也就是最大流
Dinic解决

/*
 * @Author: WildRage 
 * @Date: 2017-06-13 16:37:09 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-06-13 16:37:09 
 */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x7fffffff;
struct edge{
    int END,cap,next;
}v[500000];
int first[10005],p;
void add(int a,int b,int c){
    v[p].END=b;v[p].next=first[a];v[p].cap=c;first[a]=p++;
    v[p].END=a;v[p].next=first[b];v[p].cap=0;first[b]=p++;
}
int dis[10005];
bool vis[10005];
bool BFS(int S,int E){
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    queue<int> Q;
    Q.push(S);
    dis[S]=0;vis[S]=1;
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=first[u];i!=-1;i=v[i].next){
            if(!vis[v[i].END]&&v[i].cap>0){
                vis[v[i].END]=1;
                dis[v[i].END]=dis[u]+1;
                if(v[i].END==E)return 1;
                Q.push(v[i].END);
            }
        }
    }
    return 0;
}
int DFS(int x,int a,int E){
    if(x==E||a==0)return a;
    int flow=0,f;
    for(int i=first[x];i!=-1;i=v[i].next){
        if(dis[x]+1==dis[v[i].END]&&(f=DFS(v[i].END,min(a,v[i].cap),E))>0){
            v[i].cap-=f;
            v[i^1].cap+=f;
            flow+=f;
            a-=f;
            if(a==0)break;
        }
    }
    if(!flow)dis[x]=-1;
    return flow;
}
int Dinic(int S,int E){
    int flow=0;
    while(BFS(S,E)){
        flow+=DFS(S,INF,E);
    }
    return flow;
}
int a[105][105];
template<class T>inline void read(T &res){
    static char ch;T flag=1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
}
int Main(){
    freopen("Excalibur.in","r",stdin);
    freopen("Excalibur.out","w",stdout);
    memset(first,-1,sizeof(first));
    int m,n;
    int sum=0;
    read(m),read(n);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++){
            read(a[i][j]);
            sum+=a[i][j];
        }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            if((i&1)^(j&1)){
                add(0,n*(i-1)+j,a[i][j]);
                if(j-1>=1)add(n*(i-1)+j,n*(i-1)+j-1,INF);
                if(i-1>=1)add(n*(i-1)+j,n*(i-2)+j,INF);
                if(i+1<=m)add(n*(i-1)+j,n*(i)+j,INF);
                if(j+1<=n)add(n*(i-1)+j,n*(i-1)+j+1,INF);
            }
            else{
                add(n*(i-1)+j,n*m+1,a[i][j]);
            }
            
        }
    }
    return printf("%d",sum-Dinic(0,m*n+1));
}
int A=Main();
int main(){;}
本文作者 : NekoMio
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本文链接 : https://www.nekomio.com/2017/06/13/5/
上一篇
下一篇