CF 589F 网络流(or贪心?)

来源:互联网 发布:怎么申请淘宝店铺 编辑:程序博客网 时间:2024/05/01 20:39

题目链接:http://codeforces.com/problemset/problem/589/F


题意:有n盆菜,每个菜的上菜时间是ai-bi,要求每盆菜的品尝时间都相同,求最大的品尝时间。


思路:一开始也想到了网络流,但是没有想到压缩区域。。。(我只想到一个点一个点地建图,这个的图点可能有10^4个啊。。肯定不能用网络流),后来请教别人可以一个区间建图,流量就是区间长度,这个的话点最多300+个。。。网络流妥妥可以。。。。

做法就是找到一个区间,扫一遍所有的菜哪些菜的上菜时间是包含这个区间的,然后从s到时间区间点连一个区间长度大小的流量,时间区间点到能到的菜连一个区间长度大小的流量,最后一遍最大流搞定。

PS:神奇的贪心做法可以二分最大品尝时间,每次扫描一个单位的区间然后把这个区间分给bi最小且品尝时间没满的菜,就这样好了。。。。



#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define For(a,b,c) for(int a = b;a <= c;a++)using namespace std;typedef long long ll;const int maxn = 1000005;const int INF = 0x3f3f3f3f;const int e_maxn = 100000 * 4;const int v_maxn = 500;struct ppp{int v,nex,cap,flow,c;//分别为下一个点,下一条边,当前边容量和流量,还有费用}e[e_maxn];int head[v_maxn],dis[v_maxn],cur[v_maxn];//链表头节点,层次图中每个点所属层次,dfs所用的临时链表头int tole,N,M,s,t;//总加入边数,总输入点数和总输入边数,源点和汇点void make_edge(int u,int v,int cap,int c)//求最大流时费用不必考虑,可以省去,加上也没关系{e[tole].v = v;e[tole].flow = 0;e[tole].cap = cap;e[tole].c = c;e[tole].nex = head[u];head[u] = tole++;}void add_edge(int u,int v,int cap,int c){make_edge(u,v,cap,c);//正向边容量为cap,费用为cmake_edge(v,u,0,-c);//反向边容量为0,费用为-c}int bfs()//其中s为源点,t为汇点{queue<int> que;que.push(s);mem(dis,-1);dis[s] = 0;int temp,v;while(!que.empty()){temp = que.front();que.pop();for(int i = head[temp];~i;i = e[i].nex){v = e[i].v;if(dis[v] == -1 && e[i].cap > e[i].flow){dis[v] = dis[temp] + 1;que.push(v);}}}return dis[t] != -1;}int dfs(int x,int a){if(x == t || !a) return a;int v,f,ret = 0;for(int &i = cur[x];~i;i = e[i].nex){v = e[i].v;if((dis[v] == dis[x] + 1) && (f = dfs(v,min(a,e[i].cap - e[i].flow))) > 0){e[i].flow += f;e[i ^ 1].flow -= f;a -= f;ret += f;if(!a)break;}}return ret;}void Dinic(int &ans)//ans为最大流{while(bfs()){for(int i = 0;i <= t;i++)cur[i] = head[i];ans += dfs(s,INF);}}int mark[10005];int n;int a[105],b[105];int cal(int x){s = 0,t = v_maxn - 1;mem(head,-1);tole = 0;int from = 0;int cnt = 0;for(int i = 0;i <= 10000;i++){if(mark[i]){int ok = 0;for(int j = 0;j < n;j++){if(a[j] <= from && i <= b[j]){if(!ok){cnt++;add_edge(s,cnt,i - from,0);ok = 1;}add_edge(cnt,300 + j,i - from,0);}}from = i;}}for(int i = 0;i < n;i++)add_edge(300 + i,t,x,0);int ans = 0;Dinic(ans);if(ans == x * n)return 1;else return 0;}int main(){while(~scanf("%d",&n)){mem(mark,0);int minn = 999999999;for(int i = 0;i < n;i++){scanf("%d%d",&a[i],&b[i]);mark[a[i]] = 1;mark[b[i]] = 1;minn = min(minn,b[i] - a[i]);}int l = 0,r = minn;int ans = 0;while(l <= r){int mid = (l + r) >> 1;if(cal(mid)){ans = mid;l = mid + 1;}else r = mid - 1;}printf("%d\n",ans * n);}}




0 0
原创粉丝点击