AGC031E Snuke the Phantom Thief

Link
枚举偷了几个珠宝,然后求出按横/纵坐标升序排序之后第(i)个珠宝的合法横/纵坐标范围。
每个珠宝拆成入点出点,入点到出点有一条流量为(1)费用为价值的边。
然后再建(k)个坐标出/入点,分别和源/汇点连边,其中第(i)个出/入点代表按按横/纵坐标升序排序之后的第(i)个珠宝,它和横/纵坐标在该范围内的入/出点连边。这些边都是流量为(1)费用为(0)
那么我们会建出一个源点( ightarrow)坐标出点( ightarrow)珠宝入点( ightarrow)珠宝出点( ightarrow)坐标入点( ightarrow)汇点的分层图,求最大费用最大流就行了。

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
using i64=long long;
const int V=327,E=26087;const i64 inf=1e18;
int n,m,s,t,tot,head[V],vis[V];i64 cost,dis[V];
struct edge{int v,f;i64 c;int next;}e[E];
struct node{int x,y;i64 v;}p[V];
struct opt{int o,a,b;}op[V];
int read(){int x=0;int c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
i64 raed(){i64 x=0;int c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void add(int u,int v,int f,i64 c){e[++tot]={v,f,c,head[u]},head[u]=tot,e[++tot]={u,0,-c,head[v]},head[v]=tot;}
int update()
{
    i64 mn=inf;
    for(int u=1;u<=t;++u) if(vis[u]) for(int i=head[u];i;i=e[i].next) if(!vis[e[i].v]&&e[i].f) mn=std::min(mn,dis[e[i].v]+e[i].c-dis[u]);
    if(mn==inf) return 0;
    for(int u=1;u<=t;++u) if(vis[u]) dis[u]+=mn;
    return 1;
}
int dfs(int u,int res)
{
    if(u==t) return cost-=dis[s]*res,res;
    int use=0;vis[u]=1;
    for(int i=head[u],t;i;i=e[i].next)
	if(!vis[e[i].v]&&e[i].f&&dis[u]==dis[e[i].v]+e[i].c)
	{
	    t=dfs(e[i].v,std::min(res-use,e[i].f)),use+=t,e[i].f-=t,e[i^1].f+=t;
	    if(use==res) return use;
	}
    return use;
}
void solve(int k)
{
    static int lx[V],rx[V],ly[V],ry[V];
    tot=1,cost=0,s=2*k+2*n+1,t=s+1,memset(head+1,0,t<<2),memset(dis+1,0,t<<3);
    memset(lx+1,0,k<<2),memset(ly+1,0,k<<2),memset(rx+1,0x7f,k<<2),memset(ry+1,0x7f,k<<2);
    for(int i=1;i<=k;++i) add(s,i,1,0),add(i+n+n+k,t,1,0);
    for(int i=1;i<=n;++i) add(i+k,i+n+k,1,-p[i].v);
    for(int i=1;i<=m;++i)
	switch(op[i].o)
	{
	case'U':for(int j=1;j<=k-op[i].b;++j)ry[j]=std::min(ry[j],op[i].a-1);break;
	case'D':for(int j=op[i].b+1;j<=k;++j)ly[j]=std::max(ly[j],op[i].a+1);break;
	case'L':for(int j=op[i].b+1;j<=k;++j)lx[j]=std::max(lx[j],op[i].a+1);break;
	case'R':for(int j=1;j<=k-op[i].b;++j)rx[j]=std::min(rx[j],op[i].a-1);break;
	}
    for(int i=1;i<=k;++i) for(int j=1;j<=n;++j) if(lx[i]<=p[j].x&&p[j].x<=rx[i]) add(i,j+k,1,0);
    for(int i=1;i<=k;++i) for(int j=1;j<=n;++j) if(ly[i]<=p[j].y&&p[j].y<=ry[i]) add(j+n+k,i+n+n+k,1,0);
    do do memset(vis+1,0,t<<2);while(dfs(s,1e9));while(update());
}
int main()
{
    i64 ans=0;
    n=read();for(int i=1;i<=n;++i) p[i]={read(),read(),raed()};
    m=read();for(int i=1;i<=m;++i) op[i]={getchar(),read(),read()};
    for(int k=1;k<=n;++k) solve(k),ans=std::max(ans,cost);
    printf("%lld",ans);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12747557.html