PKU1486,ZJU1197:求出二分匹配图中的必须边;

题意:给出几张纸的覆盖范围,和几个标号的坐标,求最多的可以确定这些纸的标号
思路:每张纸作为X部,标号作为Y部,如果标号在纸中,则连一条边,求最大匹配。
检验是否有多重的匹配时,可以枚举删除匹配边,再对其进行匹配,若找到匹配边,                  
则该纸的标号不确定。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 2147483648
#define pi 3.1415926535898
#define N 1005
#define ll long long
int mat[N][N],vis[N],ans[N],n;
struct node
{
int xmin,xmax,ymin,ymax;
}p[N];
int dfs(int x)
{
   for(int i=1;i<=n;i++)
   {
       if(vis[i]==0&&mat[x][i])
  {
     vis[i]=1;
 if(ans[i]==0||dfs(ans[i]))
 {
    ans[i]=x;
return 1;
 }
  }
   }
   return 0;
}
int match()
{
int sum=0;
   for(int i=1;i<=n;i++)
   {
      memset(vis,0,sizeof(vis));
 if(dfs(i)) sum++; 
   }
   return sum;
}
int main()
{ 
int x,y;
int Case=1;
while(scanf("%d",&n)&&n)
{
  int i,j;
  memset(mat,0,sizeof(mat));
  memset(ans,0,sizeof(vis));
  for(i=1;i<=n;i++)
     scanf("%d%d%d%d",&p[i].xmin,&p[i].xmax ,&p[i].ymin ,&p[i].ymax );
  for(i=1;i<=n;i++)
  {
      scanf("%d%d",&x,&y);
  for(j=1;j<=n;j++)
  {
      if(x>=p[j].xmin &&x<=p[j].xmax &&y>=p[j].ymin &&y<=p[j].ymax )
  {
     mat[i][j]=1;//左边代表数字,右边代表字母
  }
  }
  }
  printf("Heap %d\n",Case++);//先任意求一次最大匹配
  if(match()
  int temp,cnt=0;
  for(i=1;i<=n;i++)
  {
  temp=ans[i];
  ans[i]=0;//把位置腾出来
  mat[temp][i]=0;//同时把边删掉,这样就无法达到原来的匹配
  memset(vis,0,sizeof(vis));
  if(!dfs(temp))//如果没有新的匹配方案诞生,说明这是一条关键边
  {
  cnt++;
  ans[i]=temp;
      if(cnt>1)
  printf(" ");
       printf("(%c,%d)",i-1+'A',temp);
  }
  mat[temp][i]=1;//把图复原
  }
  if(cnt==0) printf("none\n\n");
  else 
  printf("\n\n");
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值