hdu 2236(最大匹配+枚举上下界)

来源:互联网 发布:基本款斜挎包 知乎 编辑:程序博客网 时间:2024/06/09 15:18

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2236

思路:

引:为了保证每行每列只取一个元素,我们可以从二分图最大匹配的思想入手,把行和列分别看做二分图左右两部分,i-j的边权就是第i行第j列的元素的值。这样构图之后,求得的二分图最大匹配的4条边就是不在同行或同列的4个元素。

有了这个思想时候,我们只需要再保证4个元素中最大值与最小值之差尽量小就可以了,于是我们可以二分枚举最大值与最小值之差,并枚举边权值的下界,如果枚举到某个边权值的下界时该图存在最大匹配,那么就更新max,否则就更新min。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define MAXN 111 8 int map[MAXN][MAXN]; 9 int lx[MAXN],ly[MAXN];10 bool mark[MAXN];11 int vmax,vmin,MIN,mid,MAX,p,n;12 bool flag;13 14 bool dfs(int u){15    for(int i=1;i<=n;i++){16       if(map[u][i]>=p&&map[u][i]<=p+mid&&!mark[i]){17          mark[i]=true;18          if(ly[i]==-1||dfs(ly[i])){19             ly[i]=u;20             lx[u]=i;21             return true;22          }23       }24    }25    return false;26 }27 28 bool Hungry(){29    memset(lx,-1,sizeof(lx));30    memset(ly,-1,sizeof(ly));31    for(int i=1;i<=n;i++){32       memset(mark,false,sizeof(mark));33       if(!dfs(i))return false;34    }35    return true;36 }37 int main(){38    int _case;39    scanf("%d",&_case);40    while(_case--){41       scanf("%d",&n);42       vmax=-100,vmin=100;43       for(int i=1;i<=n;i++){44          for(int j=1;j<=n;j++){45             scanf("%d",&map[i][j]);46             if(map[i][j]<vmin)vmin=map[i][j];47             if(map[i][j]>vmax)vmax=map[i][j];48          }49       }50       MAX=vmax-vmin;51       MIN=0;52       while(true)53       {54          mid=(MIN+MAX)>>1;55          flag=false;56          for(p=vmin;p+mid<=vmax;p++){57             if(Hungry()){ flag=true;break; }58          }59          if(flag)MAX=mid;60          if(MIN==mid)break;61          if(!flag)MIN=mid;62       }63       printf("%d\n",MAX);64    }65    return 0;66 }
View Code

 

 

0 0
原创粉丝点击