有一个 n × m 的地图, 地图上的每一个位置可以是空地, 炮塔或是敌人. 你需要操纵炮塔消灭敌人.
对于每个炮塔都有一个它可以瞄准的方向, 你需要在它的瞄准方向上确定一个它的攻击位置,当然也可以不进行攻击. 一旦一个位置被攻击, 则在这个位置上的所有敌人都会被消灭.
保证对于任意一个炮塔, 它所有可能的攻击位置上不存在另外一个炮塔.
定义炮弹的运行轨迹为炮弹的起点和终点覆盖的区域. 你需要求出一种方案, 使得没有两条炮弹轨迹相交.
第一行两个整数 n,m.
接下来 n 行, 每行 m 个整数, 0 表示空地, −1,−2,−3,−4 分别表示瞄准上下左右的炮塔, 正整
数 p 表示表示此位置有 p 个敌人.
一行一个整数表示答案.
3 2
0 9
-4 3
0 -1
4 5
0 0 -2 0 0
-4 0 5 4 0
0 -4 3 0 6
9 0 0 -1 0
9
12
对于前 20% 的数据, n,m ≤ 5;
对于另 20% 的数据, 朝向上下的炮塔至多有 2 个;
对于另 20% 的数据, 至多有 6 个炮塔;
对于 100% 的数据, 1 ≤ n,m ≤ 50, 每个位置的敌人数量 < 1000.
这题用网络流解决问题十分巧妙,在解决相交的问题上采取了拆点的方法。
最后跑一遍最小割来求得最小代价即可。
#include
#include
#include
#include
using namespace std;
const int N=52,M=N*N<<1,inf=1e9;
struct data
{
int x,y;
}b[N*N];
int n,m,num,tot=1,p,ans,sum,s,t;
int first[M],next[M<<1],en[M<<1],w[M<<1];
int a[N][N],d[N][N],r[M],c[M];
int dis[M],gap[M],cur[M];
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline void ins(int x,int y,int z)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
w[tot]=z;
}
inline void insert(int x,int y,int z)
{
ins(x,y,z),ins(y,x,0);
}
int sap(int x,int y)
{
if(x==t) return y;
int use=0;
for(int i=cur[x];i;i=next[i])
if(w[i] && dis[x]==dis[en[i]]+1)
{
cur[x]=i;
int z=sap(en[i],min(w[i],y-use));
w[i]-=z,w[i^1]+=z,use+=z;
if(dis[s]>p || use==y) return use;
}
cur[x]=first[x];
if(!--gap[dis[x]]) dis[s]=p+1;
gap[++dis[x]]++;
return use;
}
int main()
{
n=read(),m=read();
s=++p,t=++p;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
a[i][j]=read();
if(a[i][j]<0) b[++num]=(data){i,j};
int x=d[i][j]=(i-1)*m+j;
r[x]=++p,c[x]=++p;
insert(c[x],r[x],inf);
}
for(int i=1;i<=num;i++)
{
int xx=b[i].x,yy=b[i].y,k=a[xx][yy];
int x=d[xx][yy];
if(k==-1 || k==-2) insert(s,c[x],inf); else insert(r[x],t,inf);
if(k==-1)
{
int mx=0,pos=0;
for(int j=xx;j;j--)
if(a[j][yy]>mx) mx=a[pos=j][yy];
if(!mx) continue;
sum+=mx;
for(int j=xx;j>=pos;j--)
if(j>1) insert(c[d[j][yy]],c[d[j-1][yy]],mx-(a[j][yy]<0?0:a[j][yy]));
}else
if(k==-2)
{
int mx=0,pos=0;
for(int j=xx;j<=n;j++)
if(a[j][yy]>mx) mx=a[pos=j][yy];
if(!mx) continue;
sum+=mx;
for(int j=xx;j<=pos;j++)
if(j1][yy]],mx-(a[j][yy]<0?0:a[j][yy]));
}else
if(k==-3)
{
int mx=0,pos=0;
for(int j=yy;j;j--)
if(a[xx][j]>mx) mx=a[xx][pos=j];
if(!mx) continue;
sum+=mx;
for(int j=yy;j>=pos;j--)
if(j>1) insert(r[d[xx][j-1]],r[d[xx][j]],mx-(a[xx][j]<0?0:a[xx][j]));
}else
{
int mx=0,pos=0;
for(int j=yy;j<=m;j++)
if(a[xx][j]>mx) mx=a[xx][pos=j];
if(!mx) continue;
sum+=mx;
for(int j=yy;j<=pos;j++)
if(j<m) insert(r[d[xx][j+1]],r[d[xx][j]],mx-(a[xx][j]<0?0:a[xx][j]));
}
}
for(int i=1;i<=p;i++) cur[i]=first[i];
gap[0]=p;
while(dis[s]<=p) ans+=sap(s,inf);
printf("%d",sum-ans);
return 0;
}