BZOJ 1458 士兵占领
2018.02.25
2018.02.25
给你一个$n*m$的棋盘,有的格子不可用,请在可用位置放置最少的士兵使得棋盘的第$i$行至少有$l_i$个士兵,第$i$列有$c_i$个士兵。
行向列连边,边权为1,S向行连边,边权为$l_i$,列向T连边,边权为$c_i$.
一种方法是求有上下界最小流,另一种方法是求最小费用最大流。
都能过,但是有上下界最小流速度比最小费用最大流快到不知到哪里去了。
最小流
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF (1<<30)
int m,n,k,S,T,SS,TT,du[300],depth[300],ans;
bool v[110][110];
queue<int>q;
int to[500000],nxt[500000],val[500000],head[300],tot=1;
inline void AE(int x,int y,int z)
{
to[++tot]=y,nxt[tot]=head[x],head[x]=tot,val[tot]=z;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot,val[tot]=0;
}
bool BFS(int x,int y)
{
while(!q.empty()) q.pop();
q.push(x);
memset(depth,-1,sizeof depth),depth[x]=0;
while(!q.empty())
{
int tmp=q.front();q.pop();
for(int i=head[tmp];i;i=nxt[i])
if(val[i]&&depth[to[i]]==-1)
{
depth[to[i]]=depth[tmp]+1;
if(to[i]==y) return true;
q.push(to[i]);
}
}
return false;
}
int dinic(int pos,int tgt,int left)
{
if(pos==tgt) return left;
int nleft=left;
for(int i=head[pos];i;i=nxt[i])
if(val[i]&&depth[to[i]]==depth[pos]+1)
{
int tmp=dinic(to[i],tgt,min(nleft,val[i]));
if(!tmp) depth[to[i]]=-1;
nleft-=tmp,val[i]-=tmp,val[i^1]+=tmp;
if(!nleft) break;
}
return left-nleft;
}
int main()
{
int tmp,tx,ty;
scanf("%d%d%d",&m,&n,&k),S=0,T=n+m+1,SS=n+m+2,TT=n+m+3;
for(int i=1;i<=m;++i) scanf("%d",&tmp),du[S]-=tmp,du[i]+=tmp,AE(S,i,INF-tmp);
for(int i=1;i<=n;++i) scanf("%d",&tmp),du[m+i]-=tmp,du[T]+=tmp,AE(m+i,T,INF-tmp);
while(k--) scanf("%d%d",&tx,&ty),v[tx][ty]=true;
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j)
if(!v[i][j])
AE(i,m+j,1);
for(int i=0;i<=n+m+1;++i)
{
if(du[i]>0) AE(SS,i,du[i]);
if(du[i]<0) AE(i,TT,-du[i]);
}
AE(T,S,INF);
while(BFS(SS,TT)) ans+=dinic(SS,TT,INF);
for(int i=0;i<=n+m+1;++i) if(du[i]>0) ans-=du[i];
if(ans!=0) puts("JIONG!");
else
{
ans=val[tot],val[tot]=val[tot-1]=0;
for(int i=head[SS];i;i=nxt[i]) val[i]=val[i^1]=0;
for(int i=head[TT];i;i=nxt[i]) val[i]=val[i^1]=0;
while(BFS(T,S)) ans-=dinic(T,S,INF);
printf("%d\n",ans);
}
return 0;
}
最小费用最大流
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int m,n,k,S=0,T=299,l[300],c[300],depth[300],dis[300],frm[300],pre[300],ans;
bool bad[110][110];
int to[500000],nxt[500000],val[500000],cst[500000],head[300],tot=1;
queue<int>q;
inline void AE(int x,int y,int a,int b)
{
to[++tot]=y,nxt[tot]=head[x],head[x]=tot,val[tot]=a,cst[tot]=b;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot,val[tot]=0,cst[tot]=-b;
}
bool SPFA()
{
q.push(S);
memset(dis,0x3f,sizeof dis),dis[S]=0;
frm[T]=-1;
while(!q.empty())
{
int tmp=q.front();q.pop();
for(int i=head[tmp];i;i=nxt[i])
if(val[i]&&dis[to[i]]>dis[tmp]+cst[i])
{
dis[to[i]]=dis[tmp]+cst[i];
frm[to[i]]=tmp,pre[to[i]]=i;
q.push(to[i]);
}
}
return ~frm[T];
}
int main()
{
int tmp,tx,ty;
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=m;++i) scanf("%d",l+i),AE(S,i,l[i],0);
for(int i=1;i<=n;++i) scanf("%d",c+i),AE(m+i,T,c[i],0);
for(int i=1;i<=k;++i) scanf("%d%d",&tx,&ty),bad[tx][ty]=true;
for(int i=1;i<=m;++i)
{
tmp=0;
for(int j=1;j<=n;++j) if(!bad[i][j]) tmp++;
if(tmp<l[i]) puts("JIONG!"),exit(0);
}
for(int j=1;j<=n;++j)
{
tmp=0;
for(int i=1;i<=m;++i) if(!bad[i][j]) tmp++;
if(tmp<c[j]) puts("JIONG!"),exit(0);
}
for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) if(!bad[i][j]) AE(i,m+j,1,1);
while(SPFA())
{
ans++;
for(int i=T;i!=S;i=frm[i]) val[pre[i]]--,val[pre[i]^1]++;
}
printf("%d\n",ans);
return 0;
}