标签:direct osi entry ogr ber nod put tin get
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 12104 | Accepted: 5954 |
Description
Input
Output
Sample Input
2 7 9 ooo**oooo **oo*ooo* o*oo**o** ooooooooo *******oo o*o*oo*oo *******oo 10 1 * * * o * * * * * *
Sample Output
17 5
Source
1 // 题意:给一张图,图中有两种点,一次只能覆盖相邻(上下左右)两点 2 // 求最小覆盖数 3 // 二分图最小覆盖数等于最大匹配数,匈牙利算法求最大匹配数 4 // 此题建图方面有些繁琐,看了大佬的题解后,才建图成功 5 6 7 #include <cstdio> 8 #include <cstring> 9 10 using namespace std; 11 12 const int max_h = 44; 13 const int max_w = 14; 14 15 int h,w; 16 char s[max_h][max_w]; 17 18 int n; 19 int total=0,save=0,cur; 20 int direct[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 21 22 const int max_n=500+5; 23 int cx[max_n],cy[max_n],st[max_n]; 24 bool vis[max_n]; 25 26 struct node 27 { 28 int y,nxt; 29 }; 30 // 这里数组开的小了点,但是刚好够用了,大佬在题解中开了比这大百倍的数组。不知道为什么 31 // 这个数组的最大用量,应该由add函数的使用上限决定 32 // 每遍历一个点,最多在上下左右四个方向进行一次add函数的调用,所以只需要4*max_n次即可 33 node way[2000]; 34 35 // 计算在一维数组中的位置 36 int get(int i,int j) 37 { 38 return i*w+j; 39 } 40 41 void add(int u,int v) 42 { 43 ++cur; 44 // 当前数组中存储邻接点v和st【u】 45 way[cur].y=v; 46 way[cur].nxt=st[u]; 47 // st数组存储当u的边在数组中的位置 48 st[u]=cur; 49 } 50 51 int match(int x) 52 { 53 for(int i=st[x];i;i=way[i].nxt) 54 { 55 int y=way[i].y; 56 if(!vis[y]) 57 { 58 vis[y]=1; 59 if(!cy[y] || match(cy[y])) 60 { 61 cx[x]=y; 62 cy[y]=x; 63 return 1; 64 } 65 } 66 } 67 return 0; 68 } 69 70 int XYL() 71 { 72 memset(cx,0,sizeof(cx)); 73 memset(cy,0,sizeof(cy)); 74 int ans=0; 75 for(int i=0;i<n;++i) 76 { 77 // 遍历所有节点,如果找到没有匹配的x,看能否找到与之匹配的y 78 // 这里加了一步判断,对st[i]不为0的判断,也就是对当前节点不为‘o‘的判断 79 // 不加这一个判断也可得出正确的结果,但加入后会有优化,不用再执行之后许多无用的操作 80 // 毕竟只有‘*‘的点需要匹配不是吗? 81 if(!cx[i] && st[i]) 82 { 83 memset(vis,0,sizeof(vis)); 84 ans+=match(i); 85 } 86 } 87 return ans; 88 } 89 90 int main() 91 { 92 int T; 93 scanf("%d",&T); 94 while(T--) 95 { 96 // 输入数据 97 scanf("%d %d",&h,&w); 98 for(int i=0;i<h;++i) 99 { 100 scanf("%s",s[i]); 101 } 102 103 // 初始化way数组和st数组 104 cur=0; 105 memset(st,0,sizeof(st)); 106 // n表示总节点数 107 n=h*w; 108 // total表示*的总数 109 total=0; 110 111 112 for(int i=0;i<h;++i) 113 { 114 for(int j=0;j<w;++j) 115 { 116 if(s[i][j]==‘*‘) 117 { 118 ++ total; 119 // 检查相邻四个方向 120 for(int k=0;k<4;++k) 121 { 122 int tx=i+direct[k][0]; 123 int ty=j+direct[k][1]; 124 // 在图的范围内且为*时,加边 125 if(tx>=0 && tx<h && ty>=0 && ty<w) 126 { 127 if(s[tx][ty]==‘*‘) 128 { 129 int u=get(i,j); 130 int v=get(tx,ty); 131 add(u,v); 132 // printf("add"); 133 } 134 } 135 } 136 } 137 } 138 } 139 140 //printf("cur:%d\n",tot); 141 142 printf("%d\n",total-XYL()/2); 143 } 144 return 0; 145 } 146 147 /* 148 2 149 7 9 150 ooo**oooo 151 **oo*ooo* 152 o*oo**o** 153 ooooooooo 154 *******oo 155 o*o*oo*oo 156 *******oo 157 10 1 158 * 159 * 160 * 161 o 162 * 163 * 164 * 165 * 166 * 167 * 168 */
标签:direct osi entry ogr ber nod put tin get
原文地址:https://www.cnblogs.com/jishuren/p/12236404.html