POJ-3020 Antenna Placement 最大独立集 | 状态压缩DP
题目链接:http://poj.org/problem?id=3020
大意就是,给你一张图,图中某些地方标记为‘*’,要你用1*2的圈覆盖所有的‘*',圈之间可以重叠,要求使得圈的数目最少。
开始我想的是状态压缩DP,后来发现复杂度有点高,以为会TLE。看了Discuss才知道正解是用最大独立集做,即在图上构造一张二分图,然后相邻的’*‘建立边关系,求最大独立集就可以了。至于算法的正确性,我们把独立的点和与之相邻的未盖点看做一个圈就可以了,如果少了一个独立的点,那么’*‘就会覆盖不完全,所以最大独立集就是最少的圈数。
1 //STATUS:G++_AC_0MS_908KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 using namespace std; 13 #define LL __int64 14 #define pii pair<int,int> 15 #define Max(a,b) ((a)>(b)?(a):(b)) 16 #define Min(a,b) ((a)<(b)?(a):(b)) 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define lson l,mid,rt<<1 19 #define rson mid+1,r,rt<<1|1 20 const int N=50,INF=0x3f3f3f3f,MOD=1999997; 21 const LL LLNF=0x3f3f3f3f3f3f3f3fLL; 22 23 char map[N][N]; 24 int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1}; 25 int sx[N][N],sy[N][N],p[N*N],vis[N*N],y[N*N],g[210][210]; 26 int T,n,m,nx,ny; 27 28 void getg() 29 { 30 int i,j,t,q,x,y; 31 t=1; 32 for(i=nx=0;i<n;i++) 33 for(j=t=!t;j<m;j+=2) 34 if(map[i][j]=='*')sx[i][j]=nx++; 35 t=0; 36 for(i=ny=0;i<n;i++) 37 for(j=t=!t;j<m;j+=2) 38 if(map[i][j]=='*')sy[i][j]=ny++; 39 for(i=0;i<n;i++){ 40 for(j=0;j<m;j++){ 41 if(sx[i][j]!=-1){ 42 for(q=0;q<4;q++){ 43 x=i+dx[q]; 44 y=j+dy[q]; 45 if(x>=0&&x<n && y>=0&&y<m && sy[x][y]!=-1) 46 g[sx[i][j]][sy[x][y]]=1; 47 } 48 } 49 } 50 } 51 } 52 53 int dfs(int x) 54 { 55 int v; 56 for(v=0;v<ny;v++){ 57 if(g[x][v] && !vis[v]){ 58 vis[v]=1; 59 if(p[v]==-1 || dfs(p[v])){ 60 p[v]=x; 61 return 1; 62 } 63 } 64 } 65 return 0; 66 } 67 68 int main() 69 { 70 // freopen("in.txt","r",stdin); 71 int i,j,ans; 72 scanf("%d",&T); 73 while(T--) 74 { 75 ans=0; 76 mem(sx,-1);mem(sy,-1); 77 mem(p,-1); 78 mem(g,0); 79 scanf("%d%d",&n,&m); 80 for(i=0;i<n;i++) 81 scanf("%s",map[i]); 82 83 getg(); 84 for(i=0;i<nx;i++){ 85 mem(vis,0); 86 if(dfs(i))ans++; 87 } 88 89 printf("%d\n",nx+ny-ans); 90 } 91 return 0; 92 }