#2006. 「SCOI2015」小凸玩矩阵
题目描述
小凸和小方是好朋友,小方给小凸一个 N×M N imes MN×M(N≤M N leq MN≤M)的矩阵 A AA,要求小凸从其中选出 N NN 个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的 N NN 个数中第 K KK 大的数字的最小值是多少。
输入格式
第一行给出三个整数 N NN、M MM、K KK。
接下来 N NN 行,每行 M MM 个数字,用来描述这个矩阵。
输出格式
输出选出来的 N NN 个数中第 K KK 大的数字的最小值。
样例
样例输入
3 4 2
1 5 6 6
8 3 4 3
6 8 6 3
样例输出
3
数据范围与提示
1≤K≤N≤M≤250,1≤Ai,j≤109 1 leq K leq N leq M leq 250, 1 leq A_{i, j} leq 10 ^ 91≤K≤N≤M≤250,1≤Ai,j≤109
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,k,map[260][260],a[260],b[260],ans=0x3f3f3f3f; bool vis[260]; int cmp(int x,int y){return x>y;} void check(){ for(int i=1;i<=n;i++)b[i]=a[i]; sort(b+1,b+n+1,cmp); ans=min(ans,b[k]); } void dfs(int now){ if(now==n+1){ check(); return; } for(int i=1;i<=m;i++){ if(!vis[i]){ vis[i]=1; a[now]=map[now][i]; dfs(now+1); vis[i]=0; } } } int main(){ scanf("%d%d%d",&n,&m,&k); int x; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]); dfs(1); printf("%d",ans); }
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 510 #define INF 1000000000 using namespace std; int S,T,num=1,head[maxn],n,m,k,dis[maxn],a[maxn][maxn]; struct node{int to,pre,v;}e[maxn*maxn]; void Insert(int from,int to,int v){ e[++num].to=to;e[num].v=v;e[num].pre=head[from];head[from]=num; e[++num].to=from;e[num].v=0;e[num].pre=head[to];head[to]=num; } int dinic(int x,int flow){ if(x==T||flow==0)return flow; int rest=flow; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(dis[to]==dis[x]+1&&e[i].v>0){ int delta=dinic(to,min(e[i].v,rest)); e[i].v-=delta; e[i^1].v+=delta; rest-=delta; } } return flow-rest; } bool spfa(){ memset(dis,-1,sizeof(dis)); queue<int>q;q.push(S);dis[S]=0; while(!q.empty()){ int now=q.front();q.pop(); for(int i=head[now];i;i=e[i].pre){ int to=e[i].to; if(dis[to]==-1&&e[i].v>0){ dis[to]=dis[now]+1; if(to==T)return 1; q.push(to); } } } return dis[T]!=-1; } int work(){ int res=0; while(spfa()){ res+=dinic(S,INF); } return res; } bool check(int x){ memset(head,0,sizeof(head));num=1; for(int i=1;i<=n;i++)Insert(S,i,1); for(int i=1;i<=m;i++)Insert(i+n,T,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]<=x)Insert(i,j+n,1); int res=work(); if(res>=n-k+1)return 1; return 0; } int main(){ scanf("%d%d%d",&n,&m,&k); S=0;T=n+m+1; int mx=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); mx=max(mx,a[i][j]); } int l=0,r=mx,ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } printf("%d",ans); }