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

    逆向思维:最少多少士兵=最多放多少空格。于是跑最大流就OK了。取行列为节点。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define rep(i,n) for(int i=1;i<=n;i++)
    #define clr(x,c) memset(x,c,sizeof(x))
    #define REP(i,s,t) for(int i=s;i<=t;i++)
    #define op() clr(head,0);pt=edges;
    #define qwq(x) for(edge *o=head[x];o;o=o->next)
    int read(){
    	int x=0;char c=getchar();bool f=true;
    	while(!isdigit(c)) {
    		if(c=='-') f=false;c=getchar();
    	}
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x;
    }
    const int nmax=205;
    const int maxn=1000005;
    const int inf=0x7f7f7f7f;
    struct edge{
    	int to,cap;edge *next,*rev;
    };
    edge edges[maxn],*pt,*head[nmax],*p[nmax],*cur[nmax];
    int cnt[nmax],h[nmax],g[nmax][nmax],ni[nmax][2],mi[nmax][2];
    void add(int u,int v,int w){
    	pt->to=v;pt->cap=w;pt->next=head[u];head[u]=pt++;
    }
    void adde(int u,int v,int w){
    	add(u,v,w);add(v,u,0);head[u]->rev=head[v];head[v]->rev=head[u];
    }
    int maxflow(int s,int t,int n){
    	clr(cnt,0);cnt[0]=n;clr(h,0);
    	int flow=0,a=inf,x=s;edge *e;
    	while(h[s]<n){
    		for(e=cur[x];e;e=e->next) if(e->cap>0&&h[x]==h[e->to]+1) break;
    		if(e){
    			a=min(a,e->cap);p[e->to]=cur[x]=e;x=e->to;
    			if(x==t){
    				while(x!=s) p[x]->cap-=a,p[x]->rev->cap+=a,x=p[x]->rev->to;
    				flow+=a,a=inf;
    			}
    		}else{
    			if(!--cnt[h[x]]) break;
    			h[x]=n;
    			for(e=head[x];e;e=e->next) if(e->cap>0&&h[x]>h[e->to]+1) 
    			  h[x]=h[e->to]+1,cur[x]=e;
    			cnt[h[x]]++;
    			if(x!=s) x=p[x]->rev->to;
    		}
    	}
    	return flow;
    }
    int main(){
    	op();clr(ni,0);clr(mi,0);clr(g,1);
    	int n=read(),m=read(),k=read(),u,v,s=0,t=n+m+1;
    	rep(i,n) ni[i][0]=ni[i][1]=read();
    	rep(i,m) mi[i][0]=ni[i][1]=read();
    	rep(i,k) u=read(),v=read(),ni[u][0]++,mi[v][0]++,g[u][v]=0;
    	rep(i,n) if(ni[i][0]>m){
    		printf("JIONG!
    ") ;return 0;
    	}
    	rep(j,m) if(mi[j][0]>n){
    		printf("JIONG!
    ") ;return 0;
    	}
    	rep(i,n) adde(s,i,m-ni[i][0]);
    	rep(i,m) adde(i+n,t,n-mi[i][0]);
    	rep(i,n) rep(j,m) 
    	  if(g[i][j]) adde(i,n+j,1);
    	/*REP(i,s,t) {
    		qwq(i) printf("%d ",o->to);printf("
    ");
    	}*/
    	printf("%d
    ",n*m-k-maxflow(s,t,t+1));
    	return 0;
    }
    

      

    1458: 士兵占领

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 897  Solved: 505
    [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

    HINT

     

    Source

     
    [Submit][Status][Discuss]
  • 相关阅读:
    修改注释的风格
    PHP in_array
    PHP end
    PHP each
    GitHub和SourceTree入门教程
    面试题解析(不定时更新)
    Container With Most Water
    Minimum Path Sum
    Generate Parentheses
    Unique Paths
  • 原文地址:https://www.cnblogs.com/fighting-to-the-end/p/5666172.html
Copyright © 2011-2022 走看看