1. 程式人生 > >poj 2391(二分+最大流)

poj 2391(二分+最大流)

思路:求最短時間,可以想到二分,然後判斷可行性。首先在原圖上求 floyd,得到每兩個棚之間的最短距離。然後拆點:將每個棚拆為 i 和 i’(流進和流出),添邊(i,i’,INF)。增加源點 s 和匯點 t,從 s 連邊到 i,容量為該棚現在的貓的數量,i’連邊到 t,容量為該棚的容量。若棚 i 和棚 j 之間的距離不大於 limit,則連邊(i,j’,INF), (j,i’,INF)。求最大流,若從 s 發出的邊均滿流,則在 low 和 mid 中搜索;否則在 mid 和 high 中搜索。

  1 #include<iostream>
  2 #include<cstdio>
  3
#include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define MAXN 444 8 #define MAXM 44444444 9 #define inf 1<<30 10 #define INF 1LL<<60 11 12 struct Edge{ 13 int v,cap,next; 14 }edge[MAXM]; 15 16 int n,m,NE,vs,vt,NV;
17 int head[MAXN]; 18 19 void Insert(int u,int v,int cap) 20 { 21 edge[NE].v=v; 22 edge[NE].cap=cap; 23 edge[NE].next=head[u]; 24 head[u]=NE++; 25 26 edge[NE].v=u; 27 edge[NE].cap=0; 28 edge[NE].next=head[v]; 29 head[v]=NE++; 30 } 31 32 int level[MAXN],gap[MAXN];
33 void bfs(int vt) 34 { 35 memset(level,-1,sizeof(level)); 36 memset(gap,0,sizeof(gap)); 37 level[vt]=0; 38 gap[level[vt]]++; 39 queue<int>que; 40 que.push(vt); 41 while(!que.empty()){ 42 int u=que.front(); 43 que.pop(); 44 for(int i=head[u];i!=-1;i=edge[i].next){ 45 int v=edge[i].v; 46 if(level[v]<0){ 47 level[v]=level[u]+1; 48 gap[level[v]]++; 49 que.push(v); 50 } 51 } 52 } 53 } 54 55 int pre[MAXN],cur[MAXN]; 56 int SAP(int vs,int vt) 57 { 58 bfs(vt); 59 memset(pre,-1,sizeof(pre)); 60 memcpy(cur,head,sizeof(head)); 61 int maxflow=0,aug=inf; 62 int u=pre[vs]=vs; 63 gap[0]=NV; 64 while(level[vs]<NV){ 65 bool flag=false; 66 for(int &i=cur[u];i!=-1;i=edge[i].next){ 67 int v=edge[i].v; 68 if(edge[i].cap>0&&level[u]==level[v]+1){ 69 flag=true; 70 pre[v]=u; 71 u=v; 72 aug=min(aug,edge[i].cap); 73 if(v==vt){ 74 maxflow+=aug; 75 for(u=pre[v];v!=vs;v=u,u=pre[u]){ 76 edge[cur[u]].cap-=aug; 77 edge[cur[u]^1].cap+=aug; 78 } 79 aug=inf; 80 } 81 break; 82 } 83 } 84 if(flag)continue; 85 int minlevel=NV; 86 for(int i=head[u];i!=-1;i=edge[i].next){ 87 int v=edge[i].v; 88 if(edge[i].cap>0&&level[v]<minlevel){ 89 minlevel=level[v]; 90 cur[u]=i; 91 } 92 } 93 if(--gap[level[u]]==0)break; 94 level[u]=minlevel+1; 95 gap[level[u]]++; 96 u=pre[u]; 97 } 98 return maxflow; 99 } 100 101 int now_num[MAXN],num[MAXN]; 102 long long dist[MAXN][MAXN]; 103 void Floyd() 104 { 105 for(int k=1;k<=n;k++) 106 for(int i=1;i<=n;i++) 107 for(int j=1;j<=n;j++) 108 if(dist[i][k]<INF&&dist[k][j]<INF&&dist[i][k]+dist[k][j]<dist[i][j]) 109 dist[i][j]=dist[i][k]+dist[k][j]; 110 } 111 112 void Build(long long limit) 113 { 114 NE=0; 115 memset(head,-1,sizeof(head)); 116 vs=0,vt=2*n+1,NV=2*n+2; 117 for(int i=1;i<=n;i++)Insert(vs,i,now_num[i]); 118 for(int i=1;i<=n;i++)Insert(i+n,vt,num[i]); 119 for(int i=1;i<=n;i++)Insert(i,i+n,inf); 120 for(int i=1;i<=n;i++){ 121 for(int j=i+1;j<=n;j++){ 122 if(dist[i][j]<=limit){ 123 Insert(i,j+n,inf); 124 Insert(j,i+n,inf); 125 } 126 } 127 } 128 } 129 130 int main() 131 { 132 int u,v,sum; 133 long long w,low,high,mid,ans,limit; 134 while(~scanf("%d%d",&n,&m)){ 135 limit=sum=0; 136 for(int i=1;i<=n;i++){ 137 scanf("%d%d",&now_num[i],&num[i]); 138 sum+=now_num[i]; 139 } 140 for(int i=1;i<=n;i++) 141 for(int j=1;j<=n;j++) 142 dist[i][j]=(i==j)?0:INF; 143 while(m--){ 144 scanf("%d%d%lld",&u,&v,&w); 145 limit+=w; 146 if(dist[u][v]>w){ 147 dist[u][v]=dist[v][u]=w; 148 } 149 } 150 Floyd(); 151 low=0,high=limit+1,mid,ans=-1; 152 while(low<=high){ 153 mid=(low+high)>>1; 154 Build(mid); 155 if(SAP(vs,vt)==sum){ 156 ans=mid; 157 high=mid-1; 158 }else 159 low=mid+1; 160 } 161 printf("%lld\n",ans); 162 } 163 return 0; 164 }
View Code

相關推薦

poj 2391(二分+)

思路:求最短時間,可以想到二分,然後判斷可行性。首先在原圖上求 floyd,得到每兩個棚之間的最短距離。然後拆點:將每個棚拆為 i 和 i’(流進和流出),添邊(i,i’,INF)。增加源點 s 和匯點 t,從 s 連邊到 i,容量為該棚現在的貓的數量,i’連邊到 t,容量

poj 2112(二分+)

Optimal Milking Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 6483 Accepted: 2428 Case Time Limit: 1000MS Description

poj 2455(二分+)

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using name

POJ 2455 二分

Secret Milking Machine Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8660 Accepted: 2599 Description Farmer John is cons

POJ 1149 PIGS ()

long long cst track oid set typedef stdin 1.0 scanf 連接:http://poj.org/problem?id=1149 第一道網絡流,求最大流部分基本都是模板,基本的難點在於怎樣構圖。 每一個顧客、一個源點和一個匯點構

POJ 3281 Dining(

http div tdi 最大流 .org scan right printf dining POJ 3281 Dining 題目鏈接 題意:n個牛。每一個牛有一些喜歡的食物和飲料。每種食物飲料僅僅有一個。問最大能匹配上多少僅僅牛每一個牛都能吃上喜歡的食物和喜歡的

uvalive 3231 Fair Share 公平分配問題 二分+ 右邊多流量的結點流量盡量少。

init targe memset save amp class tps blog ext /** 題目: uvalive 3231 Fair Share 公平分配問題 鏈接:https://vjudge.net/problem/UVALive-3231 題意:有m個任務

POJ 3281.Dining

span 編號 ostream eth 題目 esc pen 得到 cto Dining Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18479 Accep

POJ 3498【+拆點建圖】

code 集合 mem str ring con 我們 距離 fine 題意: 在X,Y坐標系中有N(N<=100)個冰塊...有些冰塊上有若幹只企鵝..每只企鵝一次最多跳M距離..一個冰塊在有Mi個企鵝離開..就會消失..問有哪些冰塊可以作為集合點..就是所有企鵝都

HDU4560 二分

  http://acm.hdu.edu.cn/showproblem.php?pid=4560 網路流好像經常搭配上二分和拆點。   n個歌手,m種歌曲流派(n<=m<=75) 我們想要安排儘可能多的演唱會。不過有以下條件—— 1,每場演唱會中,每個歌手要唱

G - Gasoline Gym - 101908G[二分]

題意:給出R個提供點,P個接收點,每個接收點都要接收滿,還有一個運輸的時間,問最小時間能夠完成所有的運輸。 題解:首先很容易想到費用流,當然T了 O

bzoj 1189 二分+

const noi2007 truct span find() for 問題 思路 check 題目傳送門 思路:   先預處理出每個人到每扇門的時間,用門作為起點進行bfs處理。   然後二分時間,假設時間為x,將每扇門拆成1到x,x個時間點,表示這扇門有幾個時間點是可以

bzoj 1189 二分+

題目傳送門 思路:   先預處理出每個人到每扇門的時間,用門作為起點進行bfs處理。   然後二分時間,假設時間為x,將每扇門拆成1到x,x個時間點,表示這扇門有幾個時間點是可以出去的。對於一扇門,每個時間點都向後一個時間點建邊,表示人在當前時間點到達,可以在下一時間點出去。   先將s連上所有的空地

PIGS POJ - 1149(水)

題意: 有M個豬圈,每個豬圈裡初始時有若干頭豬。一開始所有豬圈都是關閉的。依次來了N個顧客,每個顧客分別會開啟指定的幾個豬圈,從中買若干頭豬。每個顧客分別都有他能夠買的數量的上限。每個顧客走後,他開啟的那些豬圈中的豬,都可以被任意地調換到其它開著的豬圈裡,然後所有豬圈重新關上。問總共最多能賣出多少頭豬。(1

POJ 3281 Dining()

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has coo

POJ.3281 dining +拆點

POJ.3281 dining 最大流+拆點 思路清晰為啥一直WA呢 #include <iostream> #include <cstring> #include <vector> #include <algorith

UVA 1345 Jamie's Contact Groups(二分+

題意:有n個人,m個組,給出每個人想要去的分組,每個人只能去一個組,問人數最多的那個組最少有多少個人 二分一下每個組的可以放的人數,然後每個組與匯點相連,容量為二分的值,源點與每個人相連,容量為1,每個人與想去的組連邊,容量為1,跑一邊最大流判斷即可 #include

POJ 3614 Sunscreen 、多重匹配、貪心

#include<cstdio> #include<cstring> #define N 5005 #define M 2000005 #define inf 999999999 #include<algorithm> using namespace std; int n

HDU 3081 並查集+二分+

AC程式碼 #include<bits/stdc++.h> using namespace std; #define maxn 500 #define maxm 10000000 #define inf 0x3f3f3f3f int first[max

POJ 2699 列舉+

這應該說是比較神的一個題目了 題意的話,就是有n 個人,兩兩之間打比賽,每場比賽贏的人加一分,總共呢有n*(n-1)/2個比賽,然後求這樣一種人的個數,就是能贏所有比自己分高的人或者他就是分最高的人。 當然我們是求這種人可能的最大個數,   建圖的話,就要分兩種點,人和比賽