本来想着是分别求各个连通图的最小点覆盖,总感觉是正确的却WA,看了别人的解题报告,有点不懈,更不明白自己的想法为什么错呢、、最终由试了一个例子,发现我真的错了!
*.*.|. .***|* ***.|* ..*.|*
这个例子按照上边的思想答案仍是4,可惜不是4!发现漏洞了吧!所以说那样做是错的!
解题思路:
1.分别以行、列来用木板进行覆盖---依次编号
2.连接所有交叉的木板即连接覆盖同一污点的木板
3.求最大匹配==最小点覆盖数
我对该二分图的理解:
左右的点解对应着木板(行和列),而边对应着每一个污点,任一个污点都可以用行上或者列上的木板覆盖,所以求覆盖所有边的最少的点即为答案!
#include <stdio.h> #include <memory.h> #define N 1250 #define M 2500 typedef struct _Data { int r,c; }Data; Data number[52][52]; char map[52][52]; int nodevp[N],nodeu[M],next[M],ind; int R,C,num; void addedge(int v,int u) { nodeu[ind]=u; next[ind]=nodevp[v]; nodevp[v]=ind++; } void buildGraph() { int i,j,curNum; // for(i=0;i<52;i++) number[0][i]=number[i][0]=1; curNum=1; for(i=1;i<=R;i++) { for(j=1;j<=C;j++) if(map[i][j]=='*') { if(map[i][j-1]=='*') number[i][j].r=curNum; else number[i][j].r=++curNum; } ++curNum; } num=curNum; curNum=1; for(i=1;i<=C;i++) { for(j=1;j<=R;j++) if(map[j][i]=='*') { if(map[j-1][i]=='*') number[j][i].c=curNum; else number[j][i].c=++curNum; } ++curNum; } memset(nodevp,-1,sizeof(nodevp)); ind=0; for(i=1;i<=R;i++) for(j=1;j<=C;j++) if(number[i][j].r!=0) addedge(number[i][j].r,number[i][j].c); } int flag[N],pre[N]; int match(int v) { int i,u; for(i=nodevp[v];~i;i=next[i]) { u=nodeu[i]; if(!flag[u]) { if(pre[u]==-1 || (flag[u]=1,match(pre[u])) ) { pre[u]=v; return 1; } } } return 0; } void solve() { int i,ans=0; scanf("%d %d",&R,&C); for(i=0;i<52;i++) map[0][i]=map[i][0]='*'; for(i=1;i<=R;i++) scanf("%s",map[i]+1); buildGraph(); memset(pre,-1,sizeof(pre)); for(i=1;i<=num;i++) { memset(flag,0,sizeof(flag)); ans+=match(i); } printf("%d\n",ans); } int main() { // freopen("input.txt","r",stdin); solve(); return 0; }