BZOJ1458: 士兵占领 最大流

    xiaoxiao2022-06-29  37

    1458: 士兵占领

    Time Limit: 10 Sec   Memory Limit: 64 MB Submit: 917   Solved: 515 [ Submit][ Status][ Discuss]

    Description

    有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

    Input

    第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。

    Output

    输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)

    Sample Input

    4 4 4 1 1 1 1 0 1 0 3 1 4 2 2 3 3 4 3

    Sample Output

    4 数据范围 M, N <= 100, 0 <= K <= M * N

    题解:

    题目显然可以用网络流来求解: 因为想要得到最少需要摆放的士兵,我们可以转化一下问题去求最多有多少个格子不能放 我们可以把所有列,所有行抽象成n+m个点,把每一行向源点连一条边 边权是:对于每一行看看有多少个位置可以放士兵(也就是假设每排可以放m个士兵,这排有x个地方不能放士兵,这排要求必须要放y,边权就是m-x-y),对于每一列也是同理。 然后我们再搜索整个棋盘,比如坐标(x,y)处可以放棋子,就将行x所代表的点和列y所代表的点连一条边,边权为1,跑最大流就可以了,最大流的意义就是最多能找到多少个点可以不放棋子 答案ans=(n*m-k-最大流) #include<cstdio> #include<queue> #include<iostream> #include<cstring> using namespace std; const int N=305; const int M=40005; const int inf=2100000000; int C[N],L[N],n,m,k,nl[N],nc[N],ans,mp[N][N]; int from[M],to[M],nxt[M],lj[N],cnt=-1,w[M],pre[N]; void add(int f,int t,int p) { cnt++; to[cnt]=t; nxt[cnt]=lj[f]; lj[f]=cnt; w[cnt]=p; cnt++; to[cnt]=f; nxt[cnt]=lj[t]; lj[t]=cnt; w[cnt]=0; } int S,T,d[N]; queue<int>Q; bool bfs() { memset(d,0,sizeof(d)); d[0]=1; Q.push(0); while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=lj[x];i>=0;i=nxt[i]) if(w[i]&&!d[to[i]]) { d[to[i]]=d[x]+1; Q.push(to[i]); } } if(d[T]) return true; return false; } int dfs(int x,int v) { if(x==T||v==0) return v; int ret=0; for(int i=lj[x];i>=0;i=nxt[i]) if(d[to[i]]==d[x]+1) { int f=dfs(to[i],min(w[i],v)); w[i]-=f; w[i^1]+=f; v-=f; ret+=f; if(v==0) break; } return ret; } void make() { for(int i=1;i<=n;i++) add(S,i,m-L[i]-nl[i]); for(int i=1;i<=m;i++) add(i+n,T,n-C[i]-nc[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!mp[i][j]) add(i,j+n,1); } int main() { scanf("%d%d%d",&n,&m,&k); S=0,T=n+m+1; for(int i=S;i<=T;i++) lj[i]=-1; for(int i=1;i<=n;i++) scanf("%d",&L[i]); for(int i=1;i<=m;i++) scanf("%d",&C[i]); for(int i=1;i<=k;i++) { int x,y; scanf("%d%d",&x,&y); nl[x]++,nc[y]++; mp[x][y]=1; } make(); for(int i=0;i<=cnt;i++) if(w[i]<0) { printf("JIONG"); return 0; } while(bfs()) ans+=dfs(S,inf); printf("%d",n*m-k-ans); }
    转载请注明原文地址: https://ju.6miu.com/read-1125258.html

    最新回复(0)