假设我们一开始选取所有的运动项目,然后每一轮将当前选择人数最多的运动项目从我们当前的项目集合中删除,尝试更新答案。容易发现只有这样答案才可能变优,如果不动当前选取人数最多的项目,答案就不可能变优。
我这最外面那个二分是卖萌的。
#include<cstdio> #include<set> #include<cstring> #include<algorithm> using namespace std; typedef pair<int,int> Point; set<Point>S[310]; int n,m,a[310][310],b[310][310],cnts[310],ans=2147483647; int main(){ // freopen("b.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ scanf("%d",&a[i][j]); b[i][a[i][j]]=j; } } int l=1,r=n; while(l<r){ int mid=(l+r>>1); for(int j=1;j<=n;++j){ S[j].clear(); for(int k=1;k<=m;++k){ S[j].insert(make_pair(b[j][k],k)); } } for(int j=1;j<=m;++j){ memset(cnts,0,sizeof(cnts)); for(int k=1;k<=n;++k){ ++cnts[(*S[k].begin()).second]; } int maxx=-1,whi; for(int k=1;k<=m;++k){ if(cnts[k]>maxx){ maxx=cnts[k]; whi=k; } } if(maxx<=mid){ r=mid; goto OUT; } for(int k=1;k<=n;++k){ S[k].erase(make_pair(b[k][whi],whi)); } } l=mid+1; OUT:; } printf("%d ",l); // for(int i=1;i<=m;++i){ // for(int j=1;j<=n;++j){ // S[j].clear(); // S[j].insert(make_pair(b[j][i],i)); // } // for(int j=1;j<=m;++j) if(j!=i){ // memset(cnts,0,sizeof(cnts)); // for(int k=1;k<=n;++k){ // S[k].insert(make_pair(b[k][j],j)); // ++cnts[(*S[k].begin()).second]; // } // int maxx=-1,whi; // for(int k=1;k<=m;++k){ // if(cnts[k]>maxx){ // maxx=cnts[k]; // whi=k; // } // else if(cnts[k]==maxx && k==i){ // whi=k; // } // } // if(whi!=i){ // for(int k=1;k<=n;++k){ // S[k].erase(make_pair(b[k][j],j)); // } // } // else{ // ans=min(ans,maxx); // } // } // } // printf("%d ",ans); return 0; }