无题II
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1545 Accepted Submission(s): 692
Problem Description
这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。
Input
输入一个整数T表示T组数据。
对于每组数据第一行输入一个正整数n(1<=n<=100)表示矩阵的大小。
接着输入n行,每行n个数x(0<=x<=100)。
对于每组数据第一行输入一个正整数n(1<=n<=100)表示矩阵的大小。
接着输入n行,每行n个数x(0<=x<=100)。
Output
对于每组数据输出一个数表示最小差值。
Sample Input
1
4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
Sample Output
3
Author
xhd
Source
题解:二分枚举差值,然后枚举下界,建造出另一个图,做一次最小点覆盖,如果最小点覆盖值为n,则证明当前差值可行。时间复杂度有点高。。
#include<iostream> #include<cstdio> #include<cstring> #include <algorithm> #include <math.h> using namespace std; const int N = 105; int n,MIN,MAX; int graph[N][N],mp[N][N]; int linker[N]; bool vis[N]; bool dfs(int u) { for(int v=1; v<=n; v++) { if(!vis[v]&&mp[u][v]) { vis[v] = true; if(linker[v]==-1||dfs(linker[v])) { linker[v] = u; return true; } } } return false; } bool match(int mid) { int k = MAX - mid; for(int i=1; i<=k; i++) { for(int j=1; j<=n; j++) { for(int k=1; k<=n; k++) { if(graph[j][k]<=i+mid&&graph[j][k]>=i) mp[j][k] = 1; else mp[j][k]=0; } } memset(linker,-1,sizeof(linker)); int res = 0; for(int u=1; u<=n; u++) { memset(vis,false,sizeof(vis)); if(dfs(u)) res++; } if(res==n) return true; } return false; } int main() { int tcase; scanf("%d",&tcase); while(tcase--) { scanf("%d",&n); MIN=99999999,MAX=-1; for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { scanf("%d",&graph[i][j]); MIN = min(MIN,graph[i][j]); MAX = max(MAX,graph[i][j]); } } int l = MIN,r = MAX,ans = MAX-MIN; while(l<=r) { int mid = (l+r)>>1; if(match(mid)) { ans = mid; r = mid-1; } else l=mid+1; } printf("%d ",ans); } return 0; }