本文主要是介绍2020年11月25日提高组 D 不稳定的导弹系统 JZOJ 5057【GDSOI2017模拟4.13】炮塔,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
R e s u l t Result Result
H y p e r l i n k Hyperlink Hyperlink
洛谷
炮塔
D e s c r i p t i o n Description Description
一个 n × m n\times m n×m的网格上有若干个炮台,每个炮台有一个固定的方向,它可以选择打掉这个方向上任意一个点,并获得这个点上的价值(每个点的至多被获取一次价值,保证一个炮台打不到另一个炮台)
若炮台路径不相交,求最大代价
数据范围: n , m ≤ 50 n,m\leq 50 n,m≤50
S o l u t i o n Solution Solution
这么小的数据范围不是 d p dp dp就是网络流啦(显然考虑网络流嘛,毕竟这是一个取舍问题)
但是正向求貌似很难搞炮台路径相交这个恶心的点,我们考虑用可能的答案减去不合法的
显然,若我们不考虑路径相交,答案就是每个炮台在攻击路径上取个最大值就好了
若考虑路径相交,说明每台炮不能那么舒服的打到价值最高的点,而是考虑你打了某个点会对答案造成的影响
显然我们是可以预处理出来每个炮台打到每个点的价值,然后将路径看做从纵向的走向横向的(就是划分出来源点和汇点分别相连的点)
由于路径不能相交,换句话说就是没有通路,自然想到了最小割
不过这样做处理不了某种恶心人的情况,就是虽然我这条是通路,但实际上是合法的,如下图
针对左图这种情况,我们显然可以选择割掉右图中的这三条边就可以合法
但是在网络流中,它还会多割一条边使得图不连通,就恶心到了我们
解决的方法也很简单,考虑拆点使得横纵分开即可
时间复杂度: O ( f l o w ( n 2 m 2 ) ) O(flow(n^2m^2)) O(flow(n2m2))
C o d e Code Code
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define p(i,j) (((i-1)*m+j)*2)
#define q(i,j) (((i-1)*m+j)*2-1)
#define N 5100
using namespace std;int n,m,a[51][51],ans,s,t,sum;
struct node{int next,to,w;}e[N<<2];
int l[N],tot,d[N];
bool vis[N];
inline void add(int u,int v,int w)
{e[tot]=(node){l[u],v,w};l[u]=tot++;e[tot]=(node){l[v],u,0};l[v]=tot++;return;
}
inline bool bfs()
{memset(d,-1,sizeof(d));queue<int>q;d[s]=0;q.push(s);while(q.size()){int x=q.front();q.pop();for(int i=l[x];~i;i=e[i].next){int y=e[i].to;if(e[i].w&&d[y]==-1){d[y]=d[x]+1;q.push(y);if(y==t) return true;}}}return false;
}
int dfs(int x,int flow)
{if(x==t||!flow) return flow;int rest=0,k=0,f=0;for(int i=l[x];~i;i=e[i].next){int y=e[i].to;if(d[x]+1==d[y]&&e[i].w){f=dfs(y,min(flow-rest,e[i].w));if(!f) d[y]=-1;e[i].w-=f;rest+=f;e[i^1].w+=f;}}if(!rest) d[x]=-1;return rest;
}
void dinic()
{while(bfs()) sum-=dfs(s,1e9);return;
}
inline LL read()
{char c;LL d=1,f=0;while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;return d*f;
}
signed main()
{memset(l,-1,sizeof(l));n=read();m=read();s=0;t=n*m*2+1;for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) a[i][j]=read(),add(p(i,j),q(i,j),1e9);for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) if(a[i][j]<0){int mx=0;if(a[i][j]==-1) {add(s,p(i,j),1e9);for(register int k=i;k>=1;k--) mx=max(a[k][j],mx);for(register int k=i;k>=2;k--) add(p(k,j),p(k-1,j),mx-max(a[k][j],0));}if(a[i][j]==-2){add(s,p(i,j),1e9);for(register int k=i;k<=n;k++) mx=max(a[k][j],mx);for(register int k=i;k<n;k++) add(p(k,j),p(k+1,j),mx-max(a[k][j],0));}if(a[i][j]==-3){add(q(i,j),t,1e9);for(register int k=j;k>=1;k--) mx=max(a[i][k],mx);for(register int k=j;k>=2;k--) add(q(i,k-1),q(i,k),mx-max(a[i][k],0));}if(a[i][j]==-4){add(q(i,j),t,1e9);for(register int k=j;k<=m;k++) mx=max(a[i][k],mx);for(register int k=j;k<m;k++) add(q(i,k+1),q(i,k),mx-max(a[i][k],0));}sum+=mx;} dinic();printf("%lld",sum);
}
这篇关于2020年11月25日提高组 D 不稳定的导弹系统 JZOJ 5057【GDSOI2017模拟4.13】炮塔的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!