UVA -11419 SAM I AM 最小边覆盖输出路径

首先,我们要清楚,这道题它是最小边覆盖的题。但是与其他不同的是,这道题要输出路径,所以说我们又要学习如何输出二分图路径:首先,先跑一次匈牙利,然后再从残余网络从X集出发,沿着增广路线依次走,标记途径节点,最后取X未标记的和Y已标记的输出答案 

#include<iostream>

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int vis[1005];
int visx[1005],visy[1005];
int linkx[1005],linky[1005];
int E[1005][2];
int a[1005][1005];
int n,m,k;
int x,y;
int find(int u){//先跑一遍匈牙利 
for(int i=1;i<=n;i++){
if(vis[i]==0&&a[u][i]){
vis[i]=1;
if(linky[i]==0||find(linky[i])){
linkx[u]=i;linky[i]=u;
return 1;

}
}
return 0;
}
int buildtree(int u){//然后再跑一遍 
visx[u]=1;
for(int i=1;i<=n;i++){
if(visy[i]==0&&a[u][i]){
visy[i]=1;
if(linky[i]==0||buildtree(linky[i]))return 1;
}
}
return 0;
}
void solve(){
int ans=0;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
    ans+=find(i);
}
    for(int i=1;i<=n;i++){//如果这一行有炸弹,且没被访问过 
     if(linkx[i]==0&&E[i][0])buildtree(i);
}
printf("%d",ans);
    for(int i=1;i<=n;i++){
   if(visx[i]==0&&E[i][0]){//如果没有被访问过,
   //说明它这一行本来就是炸弹,因为它本来就是主动的那一方 
      printf(" r%d", i);
   }
    }
    for(int i=1;i<=m;i++){
   if(visy[i]&&E[i][1]) {//因为它是被动的那一方,所以
   //如果它被访问过,说明它这一列就要放炸弹 
      printf(" c%d", i);
   }
    }
    printf("\n");
}
void End(){
memset(a,0,sizeof(a));
memset(E,0,sizeof(E));
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
memset(linkx,0,sizeof(linkx));
memset(linky,0,sizeof(linky));
}
int main(){
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
if(n==0&&m==0&&k==0)break;
     for(int i=1;i<=k;i++){
    scanf("%d%d",&x,&y);
    a[x][y]=1;//二分图连边 
    E[x][0]=E[y][1]=1;//标记,说明这一行/列有炸弹 
     }
     solve();
     End();
    }
    return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值