思路来源
https://blog.csdn.net/wysiwygo/article/details/82710193//原题 poj3041 将问题转化为最小点覆盖
https://blog.csdn.net/niushuai666/article/details/7036897//如何求最小点覆盖是哪些点
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=36885415//代码实现
题解
part1:
图片来自思路来源第一个网址,感觉说的很好,而且原题既视感.jpg
就像点灯问题,以障碍物代边,以行或列代灯,每盏灯点亮连有它的所有边,即消掉所有障碍物。
问题等价于求哪些点构成一个最小点覆盖。
part2:
寻找具体最小点覆盖,从右边未匹配的点出发模拟找增广路,并标记所有其中所有经过的点,
由于已最大匹配,故不可能再找到增广路,所以一定是以未匹配边出发,最后一条边是已匹配边,二者交替。
遇到几条匹配的边即遇到了几个左边匹配的点,余下的即为右边匹配的点,二者之和即为匹配的点数。
故,左边标记的点(左边的点匹配的边)的存在,导致右边的点未能匹配;
右边匹配的点的存在,导致所有左边的未标记的点不能再找到增广路,二者是对称的。
故,这些点构成一个最小点覆盖。
part3:
代码,代码好坑啊调了若干次。
我们用vis[]数组记录是否被访问,在mincover部分记录是否被标记。
cx、cy数组记录该点匹配的点号。
希望以后自己再见到,能再敲出来。
心得
好几个板子,涉及到一个板子不兼容的问题。
令0-(n-1)号点为u集合,其匹配情况的数组cx[]
n-(n+m-1)号点为v集合,其匹配情况的数组cy[]
连边的时候,对v集合加n,
对于那些一个数组维护的,如vis[],如head[],就用原来的点的标号;
对于那些两个数组维护的,如cx[],cy[],超过n的就减n。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<double,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int head[4005],cnt,n,m,cx[2005],cy[2005];
bool vis[4005];
char tmp[2005];
struct edge{int to,nex,w;}e[200005];
vector<int>x,y;
void init()
{
cnt=0;
mem(head,-1);
}
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].nex=head[u];
head[u]=cnt++;
}
bool dfs(int u)
{
vis[u]=1;
for(int i=head[u];~i;i=e[i].nex)
{
int v=e[i].to;
if(!vis[v])
{
vis[v]=1;
if(cy[v-n]==-1||dfs(cy[v-n]))
{
cx[u]=v-n;
cy[v-n]=u;
return 1;
}
}
}
return 0;
}
void mincover()
{
mem(vis,0);
rep(i,0,n-1)if(cx[i]==-1)dfs(i);
rep(i,0,n-1)if(!vis[i])x.push_back(i);
rep(i,n,n+m-1)if(vis[i])y.push_back(i-n);
}
int hungary()
{
int res=0;
mem(vis,0);
mem(cx,-1);
mem(cy,-1);
rep(u,0,n-1)
{
mem(vis,0);
res+=dfs(u);
}
return res;
}
void output()
{
int len1=x.size(),len2=y.size();
printf("%d",len1);
rep(i,0,len1-1)printf(" %d",1+x[i]);
puts("");
printf("%d",len2);
rep(i,0,len2-1)printf(" %d",1+y[i]);
}
int main()
{
init();
sci(n),sci(m);
rep(i,0,n-1)
{
scanf("%s",tmp);
rep(j,0,m-1)
{
if(tmp[j]=='*')
{
add(i,n+j);
add(n+j,i);
}
}
}
int ans=hungary();
printf("%d\n",ans);
mincover();
output();
return 0;
}