题意:
给出一个r*c的矩阵,有些格子中有敌人,拥有一个炮塔可以一次消灭一整行或一整列的敌人,求最少的发射次数并输出方案
思路:
极为经典的建模
构造r个点表示r行,c个点表示c列
对于每个敌人,都连接一条对应的边
至于如何输出方案,从x集中出发按照 未选边-已选边-未选边…… 进行覆盖,
最后x的所有未标记点和y的已标记点就是答案(原因参见最小点覆盖=最大匹配的证明)
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int r,c,n,match[N],id[N],rr[N],cc[N],fm[N];
bool lk[N][N];
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
bool dfs(int x,int lb)
{
for(int i=1;i<=c;++i)
{
if(id[i]==lb||lk[x][i]==0) continue;
id[i]=lb;
if(match[i]==-1||dfs(match[i],lb))
{
match[i]=x;
return true;
}
}
return false;
}
void _dfs(int x)
{
rr[x]=1;
for(int i=1;i<=c;++i)
{
if(lk[x][i]==0||cc[i])continue;
cc[i]=1;
_dfs(match[i]);
}
}
int main()
{
while(1)
{
r=read(),c=read(),n=read();
if(!r || !c || !n) break;
for(int i=1;i<=r;++i)
for(int j=1;j<=c;++j)
lk[i][j]=0;
for(int i=1;i<=r;++i)rr[i]=0,fm[i]=-1;
for(int i=1;i<=c;++i)cc[i]=0;
for(int i=1;i<=c;++i)id[i]=0,match[i]=-1;
for(int i=1;i<=n;++i)
{
int u=read(),v=read();
lk[u][v]=1;
}
int ans=0;
for(int i=1;i<=r;++i)
if(dfs(i,i))++ans;
printf("%d ",ans);
for(int i=1;i<=c;++i)fm[match[i]]=i;
for(int i=1;i<=r;++i)
if(fm[i]==-1)_dfs(i);
for(int i=1;i<=r;++i)
if(!rr[i])printf("r%d ",i);
for(int i=1;i<=c;++i)
if(cc[i]) printf("c%d ",i);
puts("");
}
return 0;
}