POJ 3020 (二分图+最小路径覆盖)
题目链接:http://poj.org/problem?id=3020
题目大意:读入一张地图。其中地图中圈圈代表可以布置卫星的空地。*号代表要覆盖的建筑物。一个卫星的覆盖范围是其周围上下左右四个点。问最少需要几个卫星才能覆盖所有建筑物。
解题思路:
有点类似POJ 1328的覆盖题,不过那题比较简单可以贪心。这题你可以YY试试。
覆盖问题其实可以用图论解决。这题就属于最小路径覆盖,手动由一个点出发连一些路径,这样Hungry就能求出最少需要多少这样的中心点,就可以达成目标了。
本题最大的疑问是到底是建有向图,还是无向图。由于Hungry只适用于有向图,所以好像应该建有向图。但是扫描这个图的时候,Hash图上点不算简单,需要对n*m标个号,然后Hash。
建无向图其实也不是很简单,需要拆点,模拟出所谓的“有向图”来Hungry,本点放在X集,影子点放在Y集,如果有边(u,v),则u连v'(本点连影子点),对邻接矩阵每个城市相邻四个点扫一下加下边,这样自动模拟出"有向图"。
跑一遍Hungry,ans=建筑物数-match/2。(无向图match是两倍)
#include "iostream" #include "cstdio" #include "cstring" #include "string" #include "fstream" using namespace std; int G[401][401],link[401]; int map[410][410]; bool vis[801]; int Case,n,m,pos; void AddEdge(int x,int y) { G[x][y]=1; //本点连影子点 } bool dfs(int u) { for(int v=1;v<=pos;v++) { if(G[u][v]&&!vis[v]) { vis[v]=true; if(!link[v]||dfs(link[v])) { link[v]=u; return true; } } } return false; } int main() { #define fin cin ifstream fin("in.txt"); string line; cin>>Case; while(Case--) { pos=0; int res=0; cin>>n>>m; getline(cin,line); for(int i=1;i<=n;i++) //吸收残留 { getline(cin,line); for(int j=0;j<line.size();j++) if(line[j]=='*') map[i][j+1]=++pos; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(map[i][j]&&map[i-1][j]) AddEdge(map[i][j],map[i-1][j]); if(map[i][j]&&map[i+1][j]) AddEdge(map[i][j],map[i+1][j]); if(map[i][j]&&map[i][j-1]) AddEdge(map[i][j],map[i][j-1]); if(map[i][j]&&map[i][j+1]) AddEdge(map[i][j],map[i][j+1]); } } for(int i=1;i<=pos;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) res++; } res=pos-res/2; cout<<res<<endl; memset(map,0,sizeof(map)); memset(G,0,sizeof(G)); memset(link,0,sizeof(link)); } }