poj3020 Antenna Placement 二分匹配之最小路径覆盖
题目的意思大致就是,一个矩形中,有N个城市,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。
问至少放置多少个基站才能使得所有的城市都覆盖无线?
构图:行扫描所有城市,编号,如果有城市相邻就连一条边,当然如果3和4相邻,首先graph[3][4]=1,当扫描到4时graph[4][3]也连一条边,最后只需要取一半即可.求最大匹配的一半,这样可以得到所有2个相邻城市被一个基站覆盖所需要的基站数。然后再加上独立的那些基站即可。
公式是:N-最大匹配(代表所有可以和相邻城市配对的城市数)+最大匹配/2=N-最大匹配/2;
Source Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int nx, ny; // X的點數目、Y的點數目
int mx[405], my[405]; // X各點的配對對象、Y各點的配對對象
bool vy[405]; // 紀錄Graph Traversal拜訪過的點
bool adj[405][405]; // 精簡過的adjacency matrix
int xx,n,m,cc[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char g[41][11];
// 以DFS建立一棵交錯樹
bool DFS(int x)
{
for (int y=0; y<ny; ++y)
if (adj[x][y] && !vy[y])
{
vy[y] = true;
// 找到擴充路徑
if (my[y] == -1 || DFS(my[y]))
{
mx[x] = y; my[y] = x;
return true;
}
}
return false;
}
int bipartite_matching()
{
// 全部的點初始化為未匹配點。
memset(mx, -1, sizeof(mx));
memset(my, -1, sizeof(my));
// 依序把X中的每一個點作為擴充路徑的端點,
// 並嘗試尋找擴充路徑。
int c = 0;
for (int x=0; x<nx; ++x)
// if (mx[x] == -1) // x為未匹配點,這行可精簡。
{
// 開始Graph Traversal
memset(vy, false, sizeof(vy));
if (DFS(x)) c++;
}
return c;
}
void ini()
{
int a,b;
xx=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(g[i][j]=='*')
{
xx++;
a=i*m+j;
for(int h=0;h<4;h++)
{
if(i+cc[h][0]>=0&&i+cc[h][0]<n&&j+cc[h][1]>=0&&j+cc[h][1]<m&&g[i+cc[h][0]][j+cc[h][1]]=='*')
{
b=(i+cc[h][0])*m+j+cc[h][1];
adj[a][b]=1;
}
}
}
}
nx=ny=m*n;
}
main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(adj, 0, sizeof(adj));
getchar();
for(i=0;i<n;i++)
gets(g[i]);
ini();
printf("%d\n",xx-bipartite_matching()/2);
}
system("pause");
}