HDOJ1507解题报告【二分图染色】

题目地址:

  http://acm.hdu.edu.cn/showproblem.php?pid=1507

题目概述:

  给一个n*m的农场,其中有一些点是水池,现在需要你用2*1的格子去填充整个农场,保证所有的2*1的格子中没有水池并且相互之间没有重合部分,求出能放入的最大格子数并任意输出一种放置方案。

大致思路:

  首先一个n*m的矩阵一定能保证变成一张二分图,用二分图染色来建立这张二分图即可,对于水池颜色设置为-1,然后在二分图上的最大匹配即为答案,输出方案时根据匈牙利算法的left来输出就好。

  注意在转化成二分图时记得离散化,因为n*m有可能达到10000,而农场中不是水池的点最多只有50个。

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <ctime>
  7 #include <map>
  8 #include <queue>
  9 #include <cstring>
 10 #include <algorithm>
 11 using namespace std;
 12 
 13 #define sacnf scanf
 14 #define scnaf scanf
 15 #define maxn 110
 16 #define maxm 26
 17 #define inf 1061109567
 18 #define Eps 0.00001
 19 const double PI=acos(-1.0);
 20 #define mod 7
 21 #define MAXNUM 10000
 22 void Swap(int &a,int &b) {int t=a;a=b;b=t;}
 23 double Abs(double x) {return (x<0)?-x:x;}
 24 typedef long long ll;
 25 typedef unsigned int uint;
 26 
 27 int n,m,cnt=1;
 28 queue<int> q;
 29 int G[maxn][maxn],edge[maxn][2];
 30 int color[maxn][maxn][2];
 31 int vis[maxn],l[maxn];
 32 
 33 int dx[]={1,0,-1,0};
 34 int dy[]={0,1,0,-1};
 35 
 36 bool dfs(int u)
 37 {
 38     for(int i=1;i<cnt;i++)
 39     {
 40         if(!G[u][i]) continue;
 41         if(!vis[i])
 42         {
 43             vis[i]=1;
 44             if(l[i]==-1||dfs(l[i]))
 45             {
 46                 l[i]=u;
 47                 return true;
 48             }
 49         }
 50     }
 51     return false;
 52 }
 53 
 54 int hungary()
 55 {
 56     memset(l,-1,sizeof(l));
 57     int ans=0;
 58     while(!q.empty())
 59     {
 60         int i=q.front();q.pop();
 61         //printf("\n\n%d\n\n",i);
 62         memset(vis,0,sizeof(vis));
 63         if(dfs(i)) ans++;
 64     }
 65     return ans;
 66 }
 67 
 68 void paint(int x,int y,int c)
 69 {
 70     color[x][y][1]=cnt;
 71     edge[cnt][0]=x;edge[cnt][1]=y;
 72     color[x][y][0]=c;cnt++;
 73     if(c==1) q.push(color[x][y][1]);
 74     int t1=color[x][y][1];
 75     for(int i=0;i<4;i++)
 76     {
 77         int nx=x+dx[i];
 78         int ny=y+dy[i];
 79         if(nx>0&&nx<=n&&ny>0&&ny<=m&&color[nx][ny][0]!=-1)
 80         {
 81             if(color[nx][ny][0]==2)
 82             {
 83                 paint(nx,ny,c^1);
 84                 int t2=color[nx][ny][1];
 85                 G[t1][t2]=G[t2][t1]=1;
 86             }
 87             else if((color[nx][ny][0])^c)
 88             {
 89                 int t2=color[nx][ny][1];
 90                 G[t1][t2]=G[t2][t1]=1;
 91             }
 92         }
 93     }
 94 }
 95 
 96 void build_G()
 97 {
 98     for(int i=1;i<=n;i++)
 99     {
100         for(int j=1;j<=m;j++)
101         {
102             if(color[i][j][0]==2) paint(i,j,1);
103         }
104     }
105 }
106 
107 int main()
108 {
109     //freopen("data.in","r",stdin);
110     //freopen("data.out","w",stdout);
111     //clock_t st=clock();
112     while(~scanf("%d%d",&n,&m))
113     {
114         if(n==0&&m==0) break;
115         int k,x,y;scanf("%d",&k);
116         for(int i=1;i<=n;i++)
117             for(int j=1;j<=m;j++)
118                 color[i][j][0]=2;
119         for(int i=1;i<=n*m-k;i++)
120             for(int j=1;j<=n*m-k;j++)
121                 G[i][j]=0;
122         cnt=1;
123         for(int i=1;i<=k;i++)
124         {
125             scanf("%d%d",&x,&y);
126             color[x][y][0]=-1;
127         }
128         build_G();
129         int ans=hungary();
130         printf("%d\n",ans);
131         for(int i=1;i<cnt;i++)
132         {
133             if(l[i]==-1) continue;
134             printf("(%d,%d)--(%d,%d)\n",edge[i][0],edge[i][1],edge[l[i]][0],edge[l[i]][1]);
135         }
136         printf("\n");
137     }
138     //clock_t ed=clock();
139     //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC);
140     return 0;
141 }

 

posted @ 2017-03-07 16:16  CtrlKismet  阅读(139)  评论(0编辑  收藏  举报