标签:范围 int memset ons 没有 怎么 str 技术 个数
题意非常明白就是选取n个数字保证这些数字的行列不重复,使这些数字的极差最小。
看到这个数据范围,枚举没得跑了,怎么枚举?首先我们想一想一行一列只选一个,那么每行每列就一定都有选的,而且只有一个,即第i行对应着一个唯一的第j列,那么我们很容易想到匹配,要求有完美匹配,剩下的就是枚举了,枚举也要考虑优化一下,要不然枚举极差100*枚举起点100*枚举行100*dfs100*100,应该是会t掉的,但是我们可以想一想,是不是有单调性,即如果极差是x满足,比它大的都能满足,如果极差是x不满足,比他小的都不满足,这时我们可以考虑二分,log100基本可以不计(肯定没有7),这是复杂度是7*100*100*100*100=700000000,貌似并不能通过此题,别急,慢慢来,我们这样想,如果数据是比较集中的,那么显然有一大堆没有边的枚举,这是,第一个dfs之后就可应return了,而如果数据比较分散,那么有很多极差比较小的枚举前几个就return了,这个的常数甚至不到1/100,所以并不会t掉(这并不是数据水,怎么造也不容易t,当然由于T没有数据范围,所以如果T很大就。。。)
最后是代码:
#include <cstdio> #include <cstring> int n; const int maxn=100+10; int ed[maxn][maxn]; int jz[maxn][maxn]; int ma[maxn]; bool vis[maxn]; bool Dfs(int x){ vis[x]=1; for(int i=1;i<=n;i++){ if(vis[ma[i]]) continue; if(ed[x][i]) if(!ma[i]||Dfs(ma[i])){ ma[i]=x; return 1; } } return 0; } bool Pd(int a,int b){ memset(ed,0,sizeof(ed)); memset(ma,0,sizeof(ma)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(jz[i][j]<=b&&jz[i][j]>=a) ed[i][j]=1; for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(!Dfs(i)) return 0; } return 1; } bool Cl(int s){ for(int i=0;i+s<=100;i++) if(Pd(i,i+s)) return 1; return 0; } int main(){ int t; scanf("%d",&t); for(int i=1;i<=t;i++){ scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&jz[i][j]); int l=0,r=100; while(l<=r){ int mid=(l+r)/2; if(Cl(mid)) r=mid-1; else l=mid+1; } printf("%d\n",l); } return 0; }
标签:范围 int memset ons 没有 怎么 str 技术 个数
原文地址:https://www.cnblogs.com/wish-all-ac/p/12875391.html