HDU 2236 无题II

不知道为什么今天的题都要嘲讽我这个做不出“简单”游戏的蒟蒻

题意:给你一个n*n的方阵,从中选出n个数,且每行每列最多选一个,求选出的数中最大值和最小值的差,并是这个差最小。

思路:和上次的题读起来有些相似之处,但这道题并不需要KM算法,由于每行每列只能选一个数,我们直接跑匈牙利算法求出匹配即可,关于最小差的问题呢?我们可以每次枚举我们二分图匹配时边权的取值范围,只有边权在这个范围内时我们才考虑将两点进行匹配,那么我们的答案就是当区间最小且完成匹配时的区间长度,单是直接枚举区间长度会超时间,于是我们采用二分的方法进行优化。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 const int N=250;
 6 const int Inf=0x3f3f3f3f;
 7 using namespace std;
 8 int n,match[N],p,l,r,mid,g[N][N],vis[N];
 9 int dfs(int x){
10     for(int i=1;i<=n;++i){
11         if(p<=g[x][i]&&g[x][i]<=p+mid&&!vis[i]){
12             vis[i]=1;
13             if(!match[i]||dfs(match[i])){
14                 match[i]=x;
15                 return 1;
16             }
17         }
18     }
19     return 0;
20 }
21 bool work(){
22     int ans=0;
23     memset(match,0,sizeof(match));
24     for(int i=1;i<=n;++i){
25         memset(vis,0,sizeof(vis));
26         if(dfs(i)) ans++;
27     }
28     return ans==n?1:0;
29 }
30 int main(){
31     int t,Max,Min;
32     scanf("%d",&t);
33     while(t--){
34         Max=-Inf;
35         Min=Inf;
36         scanf("%d",&n);
37         for(int i=1;i<=n;++i)
38         for(int j=1;j<=n;++j){
39             scanf("%d",&g[i][j]);
40             Max=max(Max,g[i][j]);//用于求出最大区间长度 
41             Min=min(Min,g[i][j]);
42         }
43         l=0;r=Max-Min;//r是最大区间长度 
44         int ans=0;
45         while(l<=r){//二份枚举 
46             int cnt=0;
47             mid=((l+r)>>1);
48             for(p=Min;p+mid<=Max;++p){
49                 if(work()){//当前情况成立 
50                     cnt=1;
51                     break;
52                 }
53             }
54             if(cnt){//记录答案 
55                 ans=mid;
56                 r=mid-1;
57             }
58             else l=mid+1;
59         }
60         printf("%d
",ans);
61     }
62     return 0;
63 }
View Code
原文地址:https://www.cnblogs.com/li-jia-hao/p/12888267.html