ZOJ1516 Uncle Tom's Inherited Land(二分图最大匹配)

一个经典的构图:对格子进行黑白染色,黑白的点分别作XY部的点。

这一题的边就是可以出售的单位面积2的土地,边的端点就是这个土地占用的X部和Y部的两个点。

这样就建好二分图,要求最多土地的答案显然是这个二分图的最大边独立集,也就是最大匹配。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 using namespace std;
  6 #define MAXN 11111
  7 #define MAXM 111111
  8 #define INF 1<<30
  9 struct Edge{
 10     int v,cap,flow,next;
 11 }edge[MAXM];
 12 int vs,vt,NE,NV;
 13 int head[MAXN];
 14 
 15 void addEdge(int u,int v,int cap){
 16     edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
 17     edge[NE].next=head[u]; head[u]=NE++;
 18     edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
 19     edge[NE].next=head[v]; head[v]=NE++;
 20 }
 21 
 22 int level[MAXN];
 23 int gap[MAXN];
 24 void bfs(){
 25     memset(level,-1,sizeof(level));
 26     memset(gap,0,sizeof(gap));
 27     level[vt]=0;
 28     gap[level[vt]]++;
 29     queue<int> que;
 30     que.push(vt);
 31     while(!que.empty()){
 32         int u=que.front(); que.pop();
 33         for(int i=head[u]; i!=-1; i=edge[i].next){
 34             int v=edge[i].v;
 35             if(level[v]!=-1) continue;
 36             level[v]=level[u]+1;
 37             gap[level[v]]++;
 38             que.push(v);
 39         }
 40     }
 41 }
 42 
 43 int pre[MAXN];
 44 int cur[MAXN];
 45 int ISAP(){
 46     bfs();
 47     memset(pre,-1,sizeof(pre));
 48     memcpy(cur,head,sizeof(head));
 49     int u=pre[vs]=vs,flow=0,aug=INF;
 50     gap[0]=NV;
 51     while(level[vs]<NV){
 52         bool flag=false;
 53         for(int &i=cur[u]; i!=-1; i=edge[i].next){
 54             int v=edge[i].v;
 55             if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
 56                 flag=true;
 57                 pre[v]=u;
 58                 u=v;
 59                 //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
 60                 aug=min(aug,edge[i].cap-edge[i].flow);
 61                 if(v==vt){
 62                     flow+=aug;
 63                     for(u=pre[v]; v!=vs; v=u,u=pre[u]){
 64                         edge[cur[u]].flow+=aug;
 65                         edge[cur[u]^1].flow-=aug;
 66                     }
 67                     //aug=-1;
 68                     aug=INF;
 69                 }
 70                 break;
 71             }
 72         }
 73         if(flag) continue;
 74         int minlevel=NV;
 75         for(int i=head[u]; i!=-1; i=edge[i].next){
 76             int v=edge[i].v;
 77             if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
 78                 minlevel=level[v];
 79                 cur[u]=i;
 80             }
 81         }
 82         if(--gap[level[u]]==0) break;
 83         level[u]=minlevel+1;
 84         gap[level[u]]++;
 85         u=pre[u];
 86     }
 87     return flow;
 88 }
 89 
 90 bool map[111][111];
 91 int main(){
 92     int n,m,a,b,c;
 93     while(~scanf("%d%d",&n,&m) && (n||m)){
 94         memset(map,0,sizeof(map));
 95         scanf("%d",&c);
 96         while(c--){
 97             scanf("%d%d",&a,&b);
 98             --a; --b;
 99             map[a][b]=1;
100         }
101         vs=n*m; vt=vs+1; NV=vt+1; NE=0;
102         memset(head,-1,sizeof(head));
103         for(int i=0; i<n; ++i){
104             for(int j=0; j<m; ++j){
105                 if((i+j)&1) addEdge(vs,i*m+j,1);
106                 else addEdge(i*m+j,vt,1);
107                 if(map[i][j]) continue;
108                 if(i+1<n && !map[i+1][j]){
109                     if((i+j)&1) addEdge(i*m+j,(i+1)*m+j,1);
110                     else addEdge((i+1)*m+j,i*m+j,1);
111                 }
112                 if(j+1<m && !map[i][j+1]){
113                     if((i+j)&1) addEdge(i*m+j,i*m+j+1,1);
114                     else addEdge(i*m+j+1,i*m+j,1);
115                 }
116             }
117         }
118         printf("%d\n",ISAP());
119     }
120     return 0;
121 }

 

posted @ 2016-01-15 20:24  WABoss  阅读(373)  评论(0编辑  收藏  举报