hdu2236 无题II 最大匹配 + 二分搜索

  中文题目,题意大家都明白。

  看到“不同的行和列”就觉得要用二分匹配来做。要求最大值与最小值的差值最小,是通过枚举边的下限和上限来完成。

  枚举过程是这样的,在输入的过程可以记录下边权的最大值MAX和最小值MIN。那么他们的边权的差值的最大值为right = MAX -MIN ,最小值left =0。然后不断地增加边的下限,查找边权的差值,如果能得到完美匹配(匹配数等于n),那么就记录下这个差值。最后输出。这个搜索过程类似于最大流+二分搜索。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 const int N=105,INF=0x3f3f3f3f;
  8 int Map[N][N],cx[N],cy[N],dx[N],dy[N];
  9 bool bmask[N],bmap[N][N];
 10 int nx,ny,dis,ans;
 11 bool searchpath()
 12 {
 13     queue<int> q;
 14     dis=INF;
 15     memset(dx,-1,sizeof(dx));
 16     memset(dy,-1,sizeof(dy));
 17     for(int i=1;i<=nx;i++)
 18     {
 19         if(cx[i]==-1){ q.push(i); dx[i]=0; }
 20         while(!q.empty())
 21         {
 22             int u=q.front(); q.pop();
 23             if(dx[u]>dis) break;
 24             for(int v=1;v<=ny;v++)
 25             {
 26                 if(bmap[u][v]&&dy[v]==-1)
 27                 {
 28                     dy[v]= dx[u] + 1;
 29                     if(cy[v]==-1) dis=dy[v];
 30                     else
 31                     {
 32                         dx[cy[v]]= dy[v]+1;
 33                         q.push(cy[v]);
 34                     }
 35                 }
 36             }
 37         }
 38     }
 39     return dis!=INF;
 40 }
 41 int findpath(int u)
 42 {
 43     for(int v=1;v<=ny;v++)
 44     {
 45         if(!bmask[v]&&bmap[u][v]&&dy[v]==dx[u]+1)
 46         {
 47             bmask[v]=1;
 48             if(cy[v]!=-1&&dy[v]==dis) continue;
 49             if(cy[v]==-1||findpath(cy[v]))
 50             {
 51                 cy[v]=u; cx[u]=v;
 52                 return 1;
 53             }
 54         }
 55     }
 56     return 0;
 57 }
 58 void maxmatch()
 59 {
 60     ans=0;
 61     memset(cx,-1,sizeof(cx));
 62     memset(cy,-1,sizeof(cy));
 63     while(searchpath())
 64     {
 65         memset(bmask,0,sizeof(bmask));
 66         for(int i=1;i<=nx;i++)
 67             if(cx[i]==-1) ans+=findpath(i);
 68     }
 69 }
 70 void init()
 71 {
 72     memset(bmap,0,sizeof(bmap));
 73 }
 74 
 75 int main()
 76 {
 77     //freopen("test.txt","r",stdin);
 78     int i,j,k,n,cas,a,b;
 79     scanf("%d",&cas);
 80     while(cas--)
 81     {
 82         scanf("%d",&n);
 83         a=100,b=0;
 84         for(i=1;i<=n;i++)
 85             for(j=1;j<=n;j++){
 86                 scanf("%d",&Map[i][j]);
 87                 a=min(a,Map[i][j]);
 88                 b=max(b,Map[i][j]);
 89             }
 90         nx=ny=n;
 91         int L=0,R=b-a,mid,flag,res;
 92         while(L<=R)
 93         {
 94             mid=(L+R)/2;
 95             flag=0;
 96             for(k=a;k<=b;k++)
 97             {
 98                 for(i=1;i<=n;i++)
 99                     for(j=1;j<=n;j++)
100                         if(Map[i][j]>=k&&Map[i][j]<=k+mid) bmap[i][j]=1;
101                         else bmap[i][j]=0;
102                 maxmatch();
103                 if(ans==n) {flag=1;break;}
104             }
105             if(flag) {res=mid;R=mid-1;}
106             else  L=mid+1;
107         }
108         printf("%d\n",res);
109     }
110     return 0;
111 }
View Code

 

  

转载于:https://www.cnblogs.com/Potato-lover/p/3989675.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值