POJ 2112 Optimal Milking 【网络流】【flyod】【二分】
居然手写dinic一次过了,激动。。
这题构建网络流模型的思路还是蛮巧妙的,想要解题要想到两个题目里面给的暗示。
1.each milking machine process at most M cows each day,这是赤裸裸的网络流啊!由此联想到每个milk machine到汇点的capacity是M,那起点到每个cow的capacity都是1,管道里流的奶牛。那么问题变成了剩下的网络怎么建?牛与牛,机器与机器,牛与机器之间有没有管道。
2.这要想到第二点每个奶牛可以走很多次路最终到达milking machine,也就是说中间经过了哪些奶牛和机器是无关的,只有最后奶牛停在了哪个机器上是有关的。所以想到flyod一遍,求出奶牛到所有machine的最近距离;然后由于求的是最近最远距离,所以我们二分枚举。如果奶牛A到机器B的最近距离大于当前枚举的最远距离,那就走不了,capacity为0;反之capacity为1。
话说这还是我第一次写flyod。。把动态规划用在图论里解决最短路问题,真妙啊。
1 #include<iostream> 2 #include<cstring> 3 #include<deque> 4 #define INF 1000000000 5 using namespace std; 6 7 int dist[250][250],ans,K,C,M; 8 int G[250][250]; 9 10 int layer[250],vis[250]; 11 bool countlayer(){//还有没有增广路 12 memset(layer,0,sizeof(layer)); 13 deque<int> q; 14 q.push_back(0); layer[0]=1; 15 while(!q.empty()){ 16 int nd = q.front(); q.pop_front(); 17 if(nd==K+C+1) return true; 18 for(int i=1;i<=K+C+1;i++){ 19 if(G[nd][i] && layer[i]==0){ 20 layer[i]=layer[nd]+1; 21 q.push_back(i); 22 } 23 } 24 } 25 return false; 26 } 27 28 int dinic(){ 29 int max_flow=0; 30 while( countlayer() ){ 31 memset(vis,0,sizeof(vis)); 32 deque<int> q; 33 q.push_back(0); vis[0]=1; 34 while(!q.empty()){ 35 int nd=q.back(); 36 if(nd==K+C+1){//找到一条增广路 37 int minflow=INF,u; 38 for(int i=0;i<q.size()-1;i++){//从上到下的最小管道 39 int from=q[i],to=q[i+1]; 40 if(G[from][to]<minflow){ 41 minflow=G[from][to]; 42 u=from; 43 } 44 } 45 //做增广 46 for(int i=0;i<q.size()-1;i++){ 47 int from=q[i],to=q[i+1]; 48 G[from][to]-=minflow; 49 G[to][from]+=minflow; 50 } 51 max_flow+=minflow; 52 //回溯 53 while(!q.empty() && q.back()!=u ){ 54 vis[q.back()]=0; 55 q.pop_back(); 56 } 57 } 58 else{//继续往下搜 59 int i; 60 for(i=1;i<=K+C+1;i++){ 61 if( layer[nd]+1==layer[i] && vis[i]==0 && G[nd][i] ){ 62 vis[i]=1; 63 q.push_back(i); 64 break; 65 } 66 } 67 if(i==K+C+2) q.pop_back(); 68 } 69 } 70 } 71 return max_flow; 72 } 73 74 bool check(int dis){ 75 76 memset(G,0,sizeof(G)); 77 for(int i=K+1;i<=K+C;i++) G[0][i]=1; 78 for(int i=1;i<=K;i++) G[i][K+C+1]=M; 79 80 for(int i=K+1;i<=K+C;i++){ 81 for(int j=1;j<=K;j++){ 82 if(dist[i][j]<=dis) G[i][j]=1; 83 } 84 } 85 86 if( dinic()==C ) return true; 87 return false; 88 } 89 90 91 int main(){ 92 93 cin>>K>>C>>M; 94 for(int i=1;i<=K+C;i++){ 95 for(int j=1;j<=K+C;j++){ 96 cin>>dist[i][j];//k=0 97 if(dist[i][j]==0) dist[i][j]=INF; 98 } 99 } 100 //1...k milking machine 101 //k+1 k+c cows 102 103 for(int k=1;k<=K+C;k++) 104 for(int i=1;i<=K+C;i++) 105 for(int j=1;j<=K+C;j++){ 106 //i->j 中间节点小于等于k 107 dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]); 108 } 109 110 int start=INF,end=-1; 111 for(int i=K+1;i<=K+C;i++){ 112 for(int j=1;j<=K;j++){ 113 start=min(start,dist[i][j]); 114 end=max(end,dist[i][j]); 115 } 116 } 117 int mid; 118 while(end>=start){ 119 mid = (end+start)/2; 120 if( check(mid) ){ 121 ans=mid; 122 end=mid-1; 123 } 124 else start=mid+1; 125 } 126 127 cout<<ans; 128 return 0; 129 }