题意:在一个r*c的网格中,有n个目标,一次打击可以打一行或者一列目标,求最少的打击次数去消灭所有目标,同时计算出打击方式 ,如(r1 c2,表示打击第一行和第二列)。
思路:每个目标的x坐标和y坐标看做对立的两点构二分图,问题转化求最大匹配,稍微麻烦一点就是求打击方式,去学了一下代码,就码过来了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e3+5;
int left[maxn],vis[maxn],S[maxn],right[maxn];
vector<int>G[maxn];
int r,c,n;
void init()
{
for(int i=0;i<maxn;i++)
{
left[i]=right[i]=S[i]=0;
G[i].clear();
}
}
int dfs(int i)
{
S[i]=1;
for(int j=0;j<G[i].size();j++)
{
int v=G[i][j];
if(!vis[v])
{
vis[v]=1;
if(!left[v]||dfs(left[v]))
{
left[v]=i;
right[i]=v;
return 1;
}
}
}
return 0;
}
void print()
{
memset(vis,0,sizeof(vis));
memset(S,0,sizeof(S));
for(int i=1;i<=r;i++)
{
if(!right[i])
dfs(i);
}
vector<int>x,y;
for(int i=1;i<=r;i++)
if(!S[i])
x.push_back(i);
for(int i=1;i<=c;i++)
if(vis[i])
y.push_back(i);
for(int i=0;i<x.size();i++)
printf(" r%d",x[i]);
for(int i=0;i<y.size();i++)
printf(" c%d",y[i]);
printf("\n");
}
int main()
{
int kase=0;
while(~scanf("%d%d%d",&r,&c,&n)&&r&&c&&n)
{
init();
if(kase++)
printf("\n");
int x,y,ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
}
for(int i=1;i<=r;i++)
{
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
printf("%d",ans);
print();
}
}