首页 > 代码库 > Poj 2391 二分答案+最大流+拆点
Poj 2391 二分答案+最大流+拆点
时限卡的非常紧,做尽常数优化才过。。
#include <cstdio>#include <cstring>#include <cmath>#include <climits>#include <string>#include <iostream>#include <map>#include <cstdlib>#include <list>#include <set>#include <queue>#include <stack>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 505;const int maxm = maxn * maxn;const LL INF = 1e14;struct Edge { int u,v; LL w; bool operator < (const Edge &x) const { return w < x.w; }};LL dist[maxn][maxn],cow_cnt[maxn],sj_cnt[maxn],cow_sum;LL cap[maxm],v[maxm],maxedge;Edge e[maxm];int first[maxn],nxt[maxm];int n,m,s,t,ecnt,oecnt;void adde(int uu,int vv,LL ww) { v[ecnt] = vv; cap[ecnt] = ww; nxt[ecnt] = first[uu]; first[uu] = ecnt++; v[ecnt] = uu; cap[ecnt] = 0; nxt[ecnt] = first[vv]; first[vv] = ecnt++;}void floyd() { maxedge = -1; for(int k = 1;k <= n;k++) { for(int i = 1;i <= n;i++) { for(int j = 1;j <= n;j++) { dist[i][j] = min(dist[i][k] + dist[k][j],dist[i][j]); } } } oecnt = 0; for(int i = 1;i <= n;i++) { for(int j = 1;j <= n;j++) { if(dist[i][j] != INF) { maxedge = max(maxedge,dist[i][j]); e[oecnt].u = i; e[oecnt].v = j; e[oecnt].w = dist[i][j]; oecnt++; } } e[oecnt].u = i; e[oecnt].v = i; e[oecnt].w = 0; oecnt++; } sort(e,e + oecnt);}void input() { memset(first,-1,sizeof(first)); memset(nxt,-1,sizeof(nxt)); s = 0; t = (n << 1) | 1; cow_sum = 0; for(int i = 1;i <= n;i++) { for(int j = 1;j <= n;j++) { dist[i][j] = INF; } } for(int i = 1;i <= n;i++) { scanf("%lld%lld",&cow_cnt[i],&sj_cnt[i]); cow_sum += cow_cnt[i]; } for(int i = 1;i <= m;i++) { int u,v; LL w; scanf("%d%d%lld",&u,&v,&w); dist[u][v] = dist[v][u] = min(dist[u][v],w); } floyd();}void build_graph(LL minval) { memset(first,-1,sizeof(first)); ecnt = 0; for(int i = 1;i <= n;i++) { adde(i + n,t,sj_cnt[i]); adde(s,i,cow_cnt[i]); } for(int i = 0;i < oecnt;i++) { if(e[i].w > minval) break; adde(e[i].u,e[i].v + n,INF); }}int q[maxn * 2],qs,qe,level[maxn];bool bfs() { memset(level,0,sizeof(level)); qs = 0; qe = 1; q[qs] = s; level[s] = 1; while(qs < qe) { int now = q[qs++]; for(int i = first[now];i != -1;i = nxt[i]) { if(level[v[i]] == 0 && cap[i] != 0) { q[qe++] = v[i]; level[v[i]] = level[now] + 1; } } } return level[t];}LL dinic(int now,LL alpha) { if(now == t) return alpha; LL sum = 0; for(int i = first[now];i != -1 && sum < alpha;i = nxt[i]) { if(cap[i] && level[v[i]] == level[now] + 1) { LL ret = dinic(v[i],min(alpha,cap[i])); alpha -= ret; sum += ret; cap[i] -= ret; cap[i ^ 1] += ret; } } if(sum == 0) level[now] = -1; return sum;}bool ok(LL val) { LL ans = 0; build_graph(val); while(bfs()) ans += dinic(s,INF); return ans >= cow_sum;}void solve() { LL l = 1,r = maxedge,ans = -1,mid; while(l <= r) { mid = (l + r) >> 1; if(ok(mid)) { r = mid - 1; ans = mid; } else l = mid + 1; } printf("%lld\n",ans);}int main() { while(~scanf("%d%d",&n,&m)) { input(); solve(); } return 0;}
Poj 2391 二分答案+最大流+拆点
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。