您的位置:首页 > 其它

【bzoj1324】【Exca王者之剑】【最小割】

2016-03-29 07:01 375 查看

Description


 


Input

第一行给出数字N,M代表行列数.N,M均小于等于100 下面N行M列用于描述数字矩阵

Output

输出最多可以拿到多少块宝石

Sample Input

2 2

1 2

2 1

Sample Output

4

题解:转化一下就是不能选相邻的数。

那我们对图黑白染色。

从源点向黑点连权值的边。

从白点向汇点连权值的边。

黑点和白点之间连正无穷的边。

sum-最小割即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 20010
#define M 500010
#define inf 2100000000
using namespace std;
int sum,n,m,point
,next[M*2],cnt(1),a[110][110];
int dis
,cur
,gap
,pre
,T,x[4]={0,1,0,-1},y[4]={1,0,-1,0};
struct use{int st,en,v;}e[M*2];
bool f;
void add(int x,int y,int v){
next[++cnt]=point[x];point[x]=cnt;e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(int ss,int tt){
int u(ss),i,mn,ans(0);gap[0]=tt;
for (i=ss;i<=tt;i++) cur[i]=point[i];
while (dis[ss]<T){
f=false;
for (i=cur[u];i;i=next[i])
if (e[i].v&&dis[e[i].en]+1==dis[u]){
f=true;cur[u]=i;break;
}
if (f){
pre[u=e[i].en]=i;
if (u==tt){
mn=inf;
for (i=tt;i!=ss;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
ans+=mn;
for (i=tt;i!=ss;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
u=ss;
}
}
else{
gap[dis[u]]--;if (!gap[dis[u]]) return ans;
for (mn=T*2,i=point[u];i;i=next[i])
if (e[i].v) mn=min(mn,dis[e[i].en]);
gap[dis[u]=mn+1]++;cur[u]=point[u];if (u!=ss) u=e[pre[u]].st;
}
}
return ans;
}
int cal(int x,int y){return (x-1)*m+y;}
int main(){
scanf("%d%d",&n,&m);T=n*m+2;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
sum+=a[i][j];
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if ((i+j)&1){
add(1,cal(i,j)+1,a[i][j]);
for (int k=0;k<4;k++){
int xx=i+x[k],yy=j+y[k];
if (xx<1||xx>n||yy<1||yy>m) continue;
add(cal(i,j)+1,cal(xx,yy)+1,inf);
}
}
else add(cal(i,j)+1,T,a[i][j]);
cout<<sum-isap(1,T);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: