Description
Zxc接到一个任务--拯救世界。好在他有N个粉丝,Zxc把世界分成N个部分,每个粉丝处理一个部分,最后他来收尾。已知每个粉丝处理每个部分所需的时间,求拯救世界的最短时间是多少。每个人同时开始,但是不能互相帮忙。也就是说每个粉丝只能处理一个部分,并且一定要处理一个。
Input Format
第一行一个整数N,表示Zxc粉丝的个数。接下来N行,每行N个整数。第i+1行,第j个数表示第i个粉丝第j个部分所需要的时间。
Output Format
一个整数,表示最少需要的时间。
Sample Input
3 1 10 100 10 4 3 4 3 1
Sample Output
3
Hint
20%的数据满足1<=N<=25;
100%的数据满足1<=N<=800且最少需要的时间不超过10^9。
分析:看到题目首先想到的是用匈牙利找完美匹配,但是还要求时间最少,因为每个人的工作是分开的,互不干扰,所以使时间最少就是让用时最多的人用的时间u最少,二分枚举一下答案判断是否可以找到完美匹配就行了。
代码:
1 #include <cstdio> 2 #include <cstring> 3 4 int n, m, t[1000][1000]; 5 int vis[1000], from[1000]; 6 int to[1000000], nxt[1000000], first[1000], en; 7 8 int ins (int p1, int p2) 9 { 10 en++; 11 to[en] = p2; 12 nxt[en] = first[p1]; 13 first[p1] = en; 14 } 15 16 int draw (int lim) 17 { 18 memset (to, 0, sizeof (to)); 19 memset (nxt, 0, sizeof (nxt)); 20 memset (first, 0, sizeof (first)); 21 en = 0; 22 for (int i = 1; i <= n; i++) 23 for (int j = 1; j <= n; j++) 24 if (t[i][j] <= lim) ins (i, j); 25 } 26 27 bool find (int a) 28 { 29 30 for (int e = first[a]; e; e = nxt[e]) 31 { 32 if (!vis[to[e]]) 33 { 34 vis[to[e]] = 1; 35 if (from[to[e]] == -1 || find (from[to[e]])) 36 { 37 from[to[e]] = a; 38 return true; 39 } 40 } 41 } 42 return false; 43 } 44 45 bool work () 46 { 47 int ans = 0; 48 memset (from, -1, sizeof (from)); 49 for (int i = 1; i <= n; i++) 50 { 51 memset (vis, 0, sizeof (vis)); 52 ans += find (i); 53 } 54 return ans == n; 55 } 56 57 int run () 58 { 59 int l = 1, r = m, mid; 60 while (l < r) 61 { 62 mid = (l + r) >> 1; 63 draw (mid); 64 if (work ()) r = mid; 65 else l = mid + 1; 66 } 67 return r; 68 } 69 70 int main () 71 { 72 scanf ("%d", &n); m = 0; 73 for (int i = 1; i <= n; i++) 74 for (int j = 1; j <= n; j++) 75 scanf ("%d", &t[i][j]), 76 t[i][j] > m ? m = t[i][j] : 0; 77 printf ("%d", run ()); 78 }
PS:看起来好像每次都会有很多边,实际上二分下去剩得不多,用邻接矩阵一共跑了17.772s,用邻接表只跑了3.93s。(n+e只用了1.285s,ORZORZ)
时间: 2024-10-18 08:26:16