[BZOJ1324]Exca王者之剑(最小割)

=== ===

这里放传送门

=== ===

题解

一开始写这个题的时候看到什么“可以任意选择起点”还“可以停一秒”还有什么“奇数秒偶数秒”就感到八脸懵逼。。。实际上它说的“周围格子会消失”就是在告诉你如果对格子黑白染色,选了一个格子周围跟它颜色不同的那些格子就都不能选了,它说的“可以任意选择起点”还有“可以停一秒”就是在告诉你每次选择的时候可以任意决定当前选择黑点还是白点。并且如果它不能任意选择起点或者不能停一秒的话结果就没有可变性了还做个毛线。。那这就变成了一个显然的最小割问题,最后用所有格子的价值之和减去最小割就是答案。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define inc(x)(x=(x%100000)+1)
#define inf 1000000000
using namespace std;
int n,m,cnt,tot,a[110][110],num[110][110],p[10010],S,T,sum,Flow,cur[10010],d[10010];
struct edge{
    int to,flw,nxt;
}e[500010];
void add(int from,int to,int flow){
    e[tot].to=to;e[tot].flw=flow;e[tot].nxt=p[from];p[from]=tot++;
}
bool Bfs(){
    int q[100010],head,tail;
    memset(d,-1,sizeof(d));
    head=0;tail=1;
    for (int i=S;i<=T;i++) cur[i]=p[i];
    q[tail]=S;d[S]=0;
    while (head!=tail){
        int u;
        inc(head);u=q[head];
        for (int i=p[u];i!=-1;i=e[i].nxt)
          if (e[i].flw>0&&d[e[i].to]==-1){
              int v=e[i].to;
              d[v]=d[u]+1;inc(tail);q[tail]=v;
          }
    }
    return d[T]!=-1;
}
int Dinic(int u,int Min){
    if (u==T||Min==0) return Min;
    int r;
    for (int i=cur[u];i!=-1;i=e[i].nxt){
        int v=e[i].to;cur[u]=i;
        if (e[i].flw>0&&d[v]==d[u]+1&&(r=Dinic(v,min(Min,e[i].flw)))){
            e[i].flw-=r;e[i^1].flw+=r;return r;
        }
    }
    return 0;
}
int main()
{
    memset(p,-1,sizeof(p));
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++){
          scanf("%d",&a[i][j]);
          num[i][j]=++cnt;sum+=a[i][j];
      }
    S=0;T=n*m+1;
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++)
        if ((i+j)%2==0){
            int w=num[i][j];
            add(S,w,a[i][j]);add(w,S,0);
            if (i!=n){add(w,num[i+1][j],inf);add(num[i+1][j],w,0);}
            if (j!=m){add(w,num[i][j+1],inf);add(num[i][j+1],w,0);}
            if (i!=1){add(w,num[i-1][j],inf);add(num[i-1][j],w,0);}
            if (j!=1){add(w,num[i][j-1],inf);add(num[i][j-1],w,0);}
        }else{
            add(num[i][j],T,a[i][j]);add(T,num[i][j],0);
        }
    while (Bfs()){
        int r;
        while (r=Dinic(S,0x7fffffff))
          Flow+=r;
    }
    printf("%d\n",sum-Flow);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值