zoukankan      html  css  js  c++  java
  • BZOJ 1458: 士兵占领

    BZOJ 1458: 士兵占领

    标签(空格分隔): OI BZOJ 上下界网络流 最小流


    Time Limit: 10 Sec
    Memory Limit: 64 MB


    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


    Solution####

    诶省选一试前最后一个晚上调这个搞到11点,因为n、m反了,我的程序里n、m与题目意义相反
    建立M个点 (A_i)表示行的放置数量,N个点(B_j)表示列的放置数量。
    S向(A_i)连一条下界为(L_i),上界无穷大的边;
    (B_j)向T连一条下界为(C_j),上界无穷大的边。
    若(i,j)可以放置士兵则在(A_i、B_j)间连一条上界为1下界为0的边。
    跑一边上下界最小流即可
    上下界网络流
    新建超级源SS,超级汇TT。
    设点i的入边下界和为(In_i)
    设点i的出边下界和为(Out_i)
    SS向i连上界为(In_i),i向TT连上界为(Out_i)的边
    对原图中的边,设上界为up,下界为down,则改为残余网络,即下界为0,上界为up-down
    T向S连一条上界无穷大的边
    SS向TT跑一边最大流得到可行流
    T到S的边的流量为原图的总流量
    为了使总流量最小所以要使得(E_{T->S})最小。删除边T->S,尽量退流,即跑一遍T


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int read()
    {
    	int s=0,f=1;char ch=getchar();
    	while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    	while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    	return s*f;
    }
    int S,T,SS,TT,n,m,K,np;
    int A[105],B[105],jr[10005],jc[10005];
    int be[100005],bn[200005],bv[200005],bl[200005],bw=1;
    void put(int u,int v,int l)
    {bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;}
    int d[100005];
    bool spfa(int S,int T)
    {
    	for(int i=1;i<=np;i++)
    	   d[i]=10000000;
    	d[S]=1;
    	queue<int>q;
    	for(q.push(S);!q.empty();)
    	   {int u=q.front();q.pop();
    	    for(int i=be[u],v;i;i=bn[i])
    	       if(d[v=bv[i]]>d[u]+1&&bl[i])
    	         {d[v]=d[u]+1;
    	          q.push(v);
    			 }
    	   }
    	return d[T]!=10000000;
    }
    int ans;
    int dinic(int u,int mf,int T)
    {
    	if(mf==0)return 0;
    	if(u==T)return mf;
    	int sum=0;
    	for(int i=be[u],v;i;i=bn[i])
    	   if(d[v=bv[i]]==d[u]+1)
    	     {int f=dinic(v,min(mf-sum,bl[i]),T);
    	      bl[i]-=f;
    	      bl[i^1]+=f;
    	      sum+=f;
    	     }
    	return sum;
    }
    bool p[101][101];
    int main()
    {
    	m=read(),n=read(),K=read();
    	S=++np,T=++np;
    	for(int i=1;i<=m;i++)
    	   {int l=read();
    	    put(S,A[i]=++np,1e9);
    	    put(A[i],S,0);
    	    jr[np]+=l;
    	    jc[S]+=l;
    	   }
    	for(int i=1;i<=n;i++)
    	   {int l=read();
    	    put(B[i]=++np,T,1e9);
    	    put(T,B[i],0);
    	    jc[np]+=l;
    	    jr[T]+=l;
    	   }
    	for(int i=1;i<=K;i++)
    	   {int x=read(),y=read();p[x][y]=1;}
    	for(int i=1;i<=m;i++)
    	   for(int j=1;j<=n;j++)
    	      if(p[i][j]==0)
    	        put(A[i],B[j],1),put(B[j],A[i],0);
    	SS=++np,TT=++np;
    	int sumr=0;
    	for(int i=1;i<=np;i++)
    	   {if(jr[i]-jc[i]>0)put(SS,i,jr[i]-jc[i]),put(i,SS,0),sumr+=jr[i]-jc[i];
    	    else put(i,TT,jc[i]-jr[i]),put(TT,i,0);
    	   }
    	put(T,S,1e9);
    	put(S,T,0);
    	while(spfa(SS,TT))ans+=dinic(SS,1e9,TT);
    	if(ans<sumr)
    	  {printf("JIONG!
    ");return 0;}
    	ans=bl[bw];
    	bl[bw]=bl[bw-1]=0;
    	while(spfa(T,S))ans-=dinic(T,1e9,S);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    python数据处理——numpy_2
    Python数据处理——numpy_1
    MyEclipse 6.5 代码单词自动提示设置方法
    c语言 标准输入与输出
    JAVA中的NullPointerException异常
    c语言memmove()
    c语言 isalpha,isdigit,islower,isupper,isalnum等一系列函数
    c语言fflush()
    c语言 多维数组与指针
    c语言 回车符和换行符
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5239297.html
Copyright © 2011-2022 走看看