码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1458:最大流

时间:2016-01-12 23:03:14      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:

看到了M,N<=100于是才10000个点,直接建图吧,然后想想想=>看师兄题解。。。。。

将行和列作为节点,行和S相连,列和T相连,然后不是障碍的ij相连,c=1;

关键是能想到反过来求最多可以拿走多少个士兵,就能够转换为maxflow了。

--------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<iostream>
#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))
const int inf=0x3f3f3f;
int read(){
 int x=0,f=1;char c=getchar();
 while(!isdigit(c)){
  if(c==‘-‘) f=-1;
  c=getchar();
 }
 while(isdigit(c)){
  x=x*10+c-‘0‘;
  c=getchar();
 }
 return x*f;
}


struct edge{
 int to,cap;
 edge *next,*rev;
};
edge e[400000],*pt=e,*cur[205],*head[205],*p[205];
int d[205],cnt[205],vis[105][105],a[105],b[105],l[105],c[105];
void add(int u,int v,int d){
 pt->to=v;
 pt->cap=d;
 pt->next=head[u];
 head[u]=pt++;
}
void adde(int u,int v,int d){
 add(u,v,d);
 add(v,u,0);
 head[u]->rev=head[v];
 head[v]->rev=head[u];
}


int maxflow(int s,int t,int n){
 int flow=0,a=inf,x=s;
 clr(d,0);
 clr(cnt,0);
 cnt[0]=n;
 while(d[s]<n){
  edge *ee;
  for(ee=cur[x];ee;ee=ee->next)
   if(ee->cap>0&&d[ee->to]+1==d[x])
     break;
     if(ee){
      p[ee->to]=cur[x]=ee;
      a=min(a,ee->cap);
      x=ee->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[d[x]]) break;
      d[x]=n;
      for(ee=head[x];ee;ee=ee->next){
       if(ee->cap>0&&d[ee->to]+1<d[x]){
        d[x]=d[ee->to]+1;
        cur[x]=ee;
       }
      }
      cnt[d[x]]++;
      if(x!=s) x=p[x]->rev->to;
     }
 }
 return flow;


}
int main(){
 int L=read(),C=read(),k=read(),s=0,t=L+C+1,n=t+1;
 rep(i,L) l[i]=read();
 rep(i,C) c[i]=read();
 clr(vis,1);clr(a,0);clr(b,0);
 rep(i,k){
  int u=read(),v=read();
  vis[u][v]=0;a[u]++;b[v]++;
 }
 rep(i,L) if(C-a[i]<l[i]) {
     puts("JIONG!");
     return 0;
 }
 rep(i,C) if(L-b[i]<c[i]){
     puts("JIONG!");
     return 0;
 }
 rep(i,L) adde(s,i,C-a[i]-l[i]);
 rep(i,C) adde(L+i,t,L-b[i]-c[i]);
 rep(i,L)
      rep(j,C){
       if(vis[i][j])
         adde(i,L+j,1);
      }
 printf("%d\n",L*C-k-maxflow(s,t,n));
 return 0;
}

--------------------------------------------------------------------------------------

1458: 士兵占领

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

bzoj1458:最大流

标签:

原文地址:http://www.cnblogs.com/fighting-to-the-end/p/5125664.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!