1669 DINIC+二分
生活随笔
收集整理的這篇文章主要介紹了
1669 DINIC+二分
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
? ? ? 給你一些名單,和每個名單可以放在哪個分組里,現在要求你把所有的人都分到一個他屬于的分組(之一),然后問你分組中最多的那個人數最少是多少...
思路:
? ? ?二分最多的最少,然后用最大流去判斷分組是否合理,建圖如下
? ? ?? ??
? ? s 到 所有人連一條邊 流量是1
? ? 所有分組 到 t 連一條邊,流量是mid
? ? 然后把所有人和自己屬于的分組連邊,流量1
? ??
? ? 跑一邊最大流,如果答案等于 N(人數) 那么當前二分滿足
? ? ? 給你一些名單,和每個名單可以放在哪個分組里,現在要求你把所有的人都分到一個他屬于的分組(之一),然后問你分組中最多的那個人數最少是多少...
思路:
? ? ?二分最多的最少,然后用最大流去判斷分組是否合理,建圖如下
? ? ?? ??
? ? s 到 所有人連一條邊 流量是1
? ? 所有分組 到 t 連一條邊,流量是mid
? ? 然后把所有人和自己屬于的分組連邊,流量1
? ??
? ? 跑一邊最大流,如果答案等于 N(人數) 那么當前二分滿足
? ? up = mid - 1 ........
#include<stdio.h> #include<string.h> #include<queue>#define N_node 1500 + 50 #define N_edge 2000000 + 10000 #define INF 1000000000 using namespace std;typedef struct {int to ,next ,cost; }STAR;typedef struct {int x ,t; }DEP;typedef struct {int a ,b; }EDGE;STAR E[N_edge]; DEP xin ,tou; EDGE edge[N_edge]; int list[N_node] ,tot; int list1[N_node]; int deep[N_node]; char str[1000000];void add(int a ,int b ,int c) {E[++tot].to = b;E[tot].cost = c;E[tot].next = list[a];list[a] = tot;E[++tot].to = a;E[tot].cost = 0;E[tot].next = list[b];list[b] = tot; }int minn(int x ,int y) {return x < y ? x : y; }bool BFS_deep(int s ,int t ,int n) {memset(deep ,255 ,sizeof(deep));xin.x = s;xin.t = 0;deep[s] = 0;queue<DEP>q;q.push(xin);while(!q.empty()){tou = q.front();q.pop();for(int k = list[tou.x] ;k ;k = E[k].next){xin.x = E[k].to;xin.t = tou.t + 1;if(!E[k].cost || deep[xin.x] != -1)continue;deep[xin.x] = xin.t;q.push(xin);}}for(int i = 0 ;i <= n ;i ++)list1[i] = list[i];return deep[t] != -1; }int DFS_flow(int s ,int t ,int flow) {if(s == t) return flow;int nowflow = 0;for(int k = list1[s] ;k ;k = E[k].next){list1[s] = k;int to = E[k].to;int c = E[k].cost;if(deep[to] != deep[s] + 1 || ! E[k].cost)continue;int tmp = DFS_flow(to ,t ,minn(c ,flow - nowflow));nowflow += tmp;E[k].cost -= tmp;E[k^1].cost += tmp;if(nowflow == flow) break;}if(!nowflow) deep[s] = 0;return nowflow; }int DINIC(int s ,int t ,int n) {int ans = 0;while(BFS_deep(s ,t ,n)){ans += DFS_flow(s ,t ,INF);}return ans; }bool ok(int mid ,int tt ,int n ,int m) {memset(list ,0 ,sizeof(list));tot = 1;int i;for(i = 1 ;i <= n ;i ++)add(0 ,i ,1);for(i = 1 ;i <= m ;i ++)add(n + i ,n + m + 1 ,mid);for(i = 1 ;i <= tt ;i ++)add(edge[i].a ,edge[i].b + n ,1);return DINIC(0 ,n + m + 1 ,n + m + 1) == n; }int main () {int n ,m ,i ,j;while(~scanf("%d %d" ,&n ,&m) && n + m){getchar();int tt = 0;for(i = 1 ;i <= n ;i ++){gets(str);int l = strlen(str) - 1;j = 0;while(str[j] != ' ')j++;int num = 0;for(j++ ;j <= l ;j ++){if(str[j] == ' '){edge[++tt].a = i;edge[tt].b = num + 1;num = 0;continue;}num = num * 10 + str[j] - 48;}edge[++tt].a = i;edge[tt].b = num + 1;}int low ,up ,mid;low = 0 ,up = n;int ans;while(low <= up){mid = (low + up) >> 1;if(ok(mid ,tt ,n ,m)){ans = mid;up = mid - 1;}elselow = mid + 1;}printf("%d\n" ,ans);}return 0; }
總結
以上是生活随笔為你收集整理的1669 DINIC+二分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu1466 递推
- 下一篇: hdu1960 最小路径覆盖