bzoj5403 marshland 最大费用可行流
程序员文章站
2022-06-29 21:10:58
...
Description
Solution
唯一会写的题,还写挂了gg( ╯□╰ )
注意到我们放置一个石头等同于选择这个石头相邻的两个不危险的位置,且每个位置只能选一次
考虑费用流。与最小割类似,我们用危险度之和减去最大费用即为最小的答案
我们把每个点拆点连容量为1费用为0来满足不能重复选的限制,危险点的费用设为危险度
对于一个危险点往两个方向的非危险点连边。注意到有些非危险点之间不可能连边,那么我们把点分为三列:奇数行的非危险点,危险点,偶数行的非危险点
不难发现每次最多增广1的流量,当流量满m的时候就能退了。这里求得的实际上是最大费用可行流
大样例是假的,打挂了都能过orz
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const LL INF=10000000000;
const int N=40005;
const int E=800005;
struct edge {int x,y,w; LL c; int next;} e[E];
int v[55][55],id[55][55],pre[N];
int ls[N],edCnt=1;
LL dis[N];
bool vis[N],rec[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y,int w,int c) {
e[++edCnt]=(edge) {x,y,w,c,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,0,-c,ls[y]}; ls[y]=edCnt;
// printf("%d %d (%d,%d)\n", x,y,w,c);
}
bool spfa(int st,int ed) {
std:: queue <int> que;
que.push(st);
rep(i,0,ed+2) dis[i]=-INF;
dis[st]=0; vis[st]=1;
for (;!que.empty();) {
int now=que.front(); que.pop();
for (int i=ls[now];i;i=e[i].next) {
if (e[i].w>0&&dis[now]+e[i].c>dis[e[i].y]) {
dis[e[i].y]=dis[now]+e[i].c;
pre[e[i].y]=i;
if (!vis[e[i].y]) {
vis[e[i].y]=1;
que.push(e[i].y);
}
}
} vis[now]=0;
}
return dis[ed]!=-INF;
}
LL mcf(int st,int ed,int f) {
LL ret=0,tot=0;
for (;f;) {
if (!spfa(st,ed)) break;
int mn=f;
for (int i=ed;pre[i];i=e[pre[i]].x) mn=std:: min(e[pre[i]].w,mn);
for (int i=ed;pre[i];i=e[pre[i]].x) {e[pre[i]].w-=mn; e[pre[i]^1].w+=mn; tot+=e[pre[i]].c*mn;}
f-=mn; ret=std:: max(ret,tot);
}
return ret;
}
int main(void) {
freopen("data.in","r",stdin);
// freopen("marshland.out","w",stdout);
int n=read(),m=read(),k=read(),tot=0;
rep(i,1,n) rep(j,1,n) id[i][j]=++tot;
LL sum=0;
rep(i,1,n) rep(j,1,n) {
v[i][j]=read();
sum+=v[i][j];
}
rep(i,1,k) {
int x=read(),y=read();
rec[id[x][y]]=1;
}
rep(i,1,n) rep(j,1,n) if (!rec[id[i][j]]) {
add_edge(id[i][j],id[i][j]+tot,1,v[i][j]);
if (!((i+j)&1)) {
if (i&1) add_edge(id[i][j]+tot,tot*2+1,1,0);
else add_edge(0,id[i][j],1,0);
}
}
rep(i,1,n) if (!(i&1)) {
rep(j,1,n) {
if (!(j&1)) {
add_edge(id[i][j]+tot,id[i-1][j],1,0);
add_edge(id[i-1][j]+tot,id[i-1][j-1],1,0);
if (j!=n) add_edge(id[i-1][j]+tot,id[i-1][j+1],1,0);
add_edge(id[i][j]+tot,id[i][j-1],1,0);
add_edge(id[i][j-1]+tot,id[i-1][j-1],1,0);
if (i!=n) add_edge(id[i][j-1]+tot,id[i+1][j-1],1,0);
if (j!=n) add_edge(id[i][j]+tot,id[i][j+1],1,0);
if (j!=n) add_edge(id[i][j+1]+tot,id[i-1][j+1],1,0);
if (i!=n&&j!=n) add_edge(id[i][j+1]+tot,id[i+1][j+1],1,0);
if (i!=n) add_edge(id[i][j]+tot,id[i+1][j],1,0);
if (i!=n&&j!=n) add_edge(id[i+1][j]+tot,id[i+1][j+1],1,0);
if (i!=n) add_edge(id[i+1][j]+tot,id[i+1][j-1],1,0);
}
}
}
// add_edge(tot*2+2,0,m,0);
sum=sum-mcf(0,tot*2+1,m);
printf("%lld\n", sum);
return 0;
}
上一篇: 丞相和宰相的区别是什么 左右丞相的待遇又是什么样的
下一篇: H5上传本地图片并预览功能