您的位置:首页 > 其它

bzoj2547 [Ctsc2002]玩具兵 dp+二分匹配

2018-01-05 21:21 405 查看
先手玩几个小结论:

1、步兵一定和骑兵换→走的路径可转化为步兵路径+骑兵路径+步兵路径+...可匹配点

所以相当于求k*2个点到另外2*k个点的最小换次花费,这个用类似spfa的dp可搞

然后天兵只有一个,他可以任意走,所以坐标可以是任意值,显然最有利的方法是直接把一个送到目标点

所以用的魔法次数==天兵送的人数

所以枚举次数,然后依次加上<=次数的边,然后跑兵和目标点的二分匹配,看加上天兵送的人是不是正好跑满

码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
#define inf 9999999
int hou[100005],ans,dis[100005],xia[100005],yuan[100005],zhong[100005],zhi[100005],tot=-1,i,j,l,k,lin0,lin1,h[105][105],d[105][105][3],m,n,T,S,t,x[55],y[55],xx[55],yy[55],xxx[55*3],yyy[55*3],zzz[55*3];
queue<int>qx,qy,q;
vector<int>bianx[100*100],biany[100*100];
bool vis[105][105];
void dp(int xh,int lx)
{int i,j;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
d[i][j][0]=d[i][j][1]=999999;
if(lx==0)
{
d[x[xh]][y[xh]][lx^1]=0;
d[x[xh]][y[xh]][lx]=1;
qx.push(x[xh]);
qy.push(y[xh]);
}else
{
d[xx[xh]][yy[xh]][lx^1]=0;
d[xx[xh]][yy[xh]][lx]=1;
qx.push(xx[xh]);
qy.push(yy[xh]);
}
while(!qx.empty())
{
int stx=qx.front();
int sty=qy.front();
vis[stx][sty]=0;
qx.pop();qy.pop();
if(stx-1>=1)
{
lin0=d[stx-1][sty][0]; lin1=d[stx-1][sty][1];
if(h[stx-1][sty]<=h[stx][sty])
{
d[stx-1][sty][0]=min(d[stx-1][sty][0],min(d[stx][sty][0],d[stx][sty][1]+1));
}
if(h[stx-1][sty]>=h[stx][sty])
{
d[stx-1][sty][1]=min(d[stx-1][sty][1],min(d[stx][sty][1],d[stx][sty][0]+1));
}
if((lin0!=d[stx-1][sty][0]||lin1!=d[stx-1][sty][1])&& vis[stx-1][sty]==0)//有更新
{
qx.push(stx-1);qy.push(sty);
}
}
if(sty-1>=1)
{
lin0=d[stx][sty-1][0]; lin1=d[stx][sty-1][1];
if(h[stx][sty-1]<=h[stx][sty])
{
d[stx][sty-1][0]=min(d[stx][sty-1][0],min(d[stx][sty][0],d[stx][sty][1]+1));
}
if(h[stx][sty-1]>=h[stx][sty])
{
d[stx][sty-1][1]=min(d[stx][sty-1][1],min(d[stx][sty][1],d[stx][sty][0]+1));
}
if((lin0!=d[stx][sty-1][0]||lin1!=d[stx][sty-1][1])&& vis[stx][sty-1]==0)//有更新
{
qx.push(stx);qy.push(sty-1);
}
}
if(stx+1<=m)
{
lin0=d[stx+1][sty][0]; lin1=d[stx+1][sty][1];
if(h[stx+1][sty]<=h[stx][sty])
{
d[stx+1][sty][0]=min(d[stx+1][sty][0],min(d[stx][sty][0],d[stx][sty][1]+1));
}
if(h[stx+1][sty]>=h[stx][sty])
{
d[stx+1][sty][1]=min(d[stx+1][sty][1],min(d[stx][sty][1],d[stx][sty][0]+1));
}
if((lin0!=d[stx+1][sty][0]||lin1!=d[stx+1][sty][1])&& vis[stx+1][sty]==0)//有更新
{
qx.push(stx+1);qy.push(sty);
}
}
if(sty+1<=n)
{
lin0=d[stx][sty+1][0]; lin1=d[stx][sty+1][1];
if(h[stx][sty+1]<=h[stx][sty])
{
d[stx][sty+1][0]=min(d[stx][sty+1][0],min(d[stx][sty][0],d[stx][sty][1]+1));
}
if(h[stx][sty+1]>=h[stx][sty])
{
d[stx][sty+1][1]=min(d[stx][sty+1][1],min(d[stx][sty][1],d[stx][sty][0]+1));
}
if((lin0!=d[stx][sty+1][0]||lin1!=d[stx][sty+1][1])&& vis[stx][sty+1]==0)//有更新
{
qx.push(stx);qy.push(sty+1);
}
}
}
for(i=1;i<=t;i++)
{
bianx[min(d[xxx[i]][yyy[i]][0],d[xxx[i]][yyy[i]][1])].push_back(xh+k*lx);
biany[min(d[xxx[i]][yyy[i]][0],d[xxx[i]][yyy[i]][1])].push_back(k*2+i);
}
}
void jian(int x,int y,int z)
{
hou[++tot]=yuan[x],yuan[x]=tot,zhi[tot]=z,zhong[tot]=y;
}
void jia (int x,int y,int z)
{
jian(x,y,z);
jian(y,x,0);
}
bool bfs()
{
int i;
memset(dis,0x7f,sizeof(dis));
for(int i=1;i<=T;i++)
xia[i]=yuan[i];
q.push(S);
dis[S]=1;
while(!q.empty())
{
int st=q.front();
q.pop();
for(i=xia[st];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(dis[nd]>inf&&zhi[i])
{
dis[nd]=dis[st]+1;
q.push(nd);
}
}
}
return dis[T]<inf ;
}
int dfs(int now,int T,int limit)
{
if(!limit||now==T)return limit;
int i,f=0,flow=0;
for(i=xia[now];i!=-1;i=hou[i])
{
xia[now]=i;
int nd=zhong[i];
if(dis[nd]==dis[now]+1&&(f=dfs(nd,T,min(limit,zhi[i]))))
{
flow+=f;
limit-=f;
zhi[i]-=f;
zhi[i^1]+=f;
if(!limit)break;
}
}
return flow;
}
int dinic()
{
int daan=0;
while(bfs())
{
daan+=dfs(S,T,99999);
}
return daan;
}
int work()
{
for(i=0;i<=2*k+1;i++)//枚举上限
{
for(j=0;j<bianx[i].size();j++)// 加边
{
jia(bianx[i][j],biany[i][j],1);
}
ans+=dinic();
if(2*k-ans<=i)return i;
}
}
int main()
{
memset(yuan,-1,sizeof(yuan));
scanf("%d%d%d%d",&m,&n,&k,&t);
S=2*k+t+1;T=2*k+t+2;
for(i=1;i<=k;i++)
{
scanf("%d%d",&x[i],&y[i]);
jia(S,i,1);
}
for(i=1;i<=k;i++)
{
scanf("%d%d",&xx[i],&yy[i]);
jia(S,i+k,1);
}
scanf("%d%d",&x[k+1],&y[k+1]);
for(i=1;i<=t;i++)
{
scanf("%d%d%d",&xxx[i],&yyy[i],&zzz[i]);
jia(2*k+i,T,zzz[i]);

}
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&h[i][j]);
}
for(l=1;l<=k;l++)
dp(l,0);
for(l=1;l<=k;l++)
dp(l,1);
printf("%d",work()) ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: