您的位置:首页 > 理论基础 > 计算机网络

POJ2112解题报告【网络流-初级-isap+floyd_warshall+二分】

2012-07-03 15:02 337 查看
题目连接:http://poj.org/problem?id=2112

题意:有C头牛和K个挤奶机,每个挤奶机最多能为M头牛挤奶,他们在农场的不同位置。牛和牛、牛和机器之间可能有路,牛只能沿着路移动。给出路的长度,问要让这些牛都挤完奶,所有牛中走得最远的牛的行走路程最短是多少?

解题思路:首先要建图,把每个牛和挤奶机都看成节点,节点间的边既是他们之间的路的长度。然后用floyd算法,求出每个点之间的最短距离。记录最长的距离,然后二分该距离。再建一个网络流的图,图中包括一个源点、一个汇点、挤奶机的点、牛的点,源点和牛之间都连上容量为1的边,牛和挤奶机之间的距离如果小于mid(之前二分的距离),那么就建立一条容量为1的边,每个挤奶机和汇点之间都建立一条容量为K的边。然后ISAP算法求最大流,如果最大流等于C,向下二分否则向上二分。

算法:ISAP+floyd_walshall+二分

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>

//#define r(x,date) (*((STRUCT*)x).date)
//#define dp(i,j) dp[i][j]
//#define dp(i,j,k) dp[i][j][k]
#define INF 0x7ffffff
#define ff(i,from,to) for(i=from;i<=to;i++)
#define rff(i,from,to) for(i=from;i>=to;i--)
#define ll long long
#define MAX_SIDE 110000
#define MAX_NODE 300
#define mset(a,num) memset(a,num,sizeof(a))
using namespace std;

template<class T>bool myfun_upmax(T &a,const T&b){return b>a?a=b,1:0;}
template<class T>bool myfun_upmin(T &a,const T&b){return b<a?a=b,1:0;}
template<class T>void myfun_swap(T &a,T &b){T temp;temp=a;a=b;b=temp;}
template<class T>T myfun_max(const T a,const T b){return a>b?a:b;}
template<class T>T myfun_min(const T a,const T b){return a<b?a:b;}

int cmp(const void *a,const void *b){
return 0;
}

inline void readint(int &ret) {
char c;
do {	c = getchar();
} while(c < '0' || c > '9');
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
}

int node[MAX_NODE];
struct SIDE{
int to,next,c;
SIDE(){}
SIDE(int to,int next,int c):to(to),next(next),c(c){}
}side[MAX_SIDE];

int top;
void add_side(int u,int v,int c){
side[top]=SIDE(v,node[u],c);
node[u]=top++;
side[top]=SIDE(u,node[v],0);
node[v]=top++;
}

int START,END,SIZE;
int gap[MAX_NODE],pre[MAX_NODE],dis[MAX_NODE],cur[MAX_NODE];
int sap(){
int maxflow=0;
int aug=INF;
int u=START,v;
for(int i=0;i<SIZE;i++){
gap[i]=dis[i]=0;
cur[i]=node[i];
}

gap[START]=SIZE;
pre[START]=START;
while(dis[u]<SIZE){
for(int &i=cur[u];i!=-1;i=side[i].next){
v=side[i].to;
if( side[i].c && dis[u]==dis[v]+1)break;
}

if(cur[u]!=-1){
myfun_upmin(aug,side[cur[u]].c);
pre[v]=u;u=v;
if(u==END){
maxflow+=aug;
while(u!=START){
u=pre[u];
side[cur[u]].c-=aug;
side[cur[u]^1].c+=aug;
}
aug=INF;
}
}else{
int min_dis=SIZE;
for(int i=node[u];i!=-1;i=side[i].next){
v=side[i].to;
if(side[i].c && myfun_upmin(min_dis,dis[v]))
cur[u]=i;
}
if(--gap[dis[u]]==0)break;
++gap[dis[u]=min_dis+1];
u=pre[u];
}
}
return maxflow;
}

int K,C;
int N;
int matrix[MAX_NODE][MAX_NODE];
int floyd_warshall(){
int MAX=0;
for(int k=0;k<N;k++){
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
if(i!=j && matrix[i][k]+matrix[k][j]<matrix[i][j]){
matrix[i][j]=matrix[i][k]+matrix[k][j];
if(matrix[i][j]<INF && matrix[i][j]>MAX)
MAX=matrix[i][j];
}
}
}
return MAX;
}

int M;
void build(int limit){
//length not less than the limit
top=0;
for(int i=0;i<N+2;i++)node[i]=-1;
for(int i=0;i<K;i++){
for(int j=K;j<N;j++){
if(matrix[i][j]<=limit)
add_side(j,i,1);
}
}
int i;
for(i=0;i<K;i++){
add_side(i,END,M);
}
for(;i<N;i++){
add_side(START,i,1);
}
}

int solve(int low,int high){
while(low<=high){
int mid=low+(high-low)/2;
build(mid);
int r=sap();
if(r==C)high=mid-1;
else low=mid+1;
}
return low;
}

int main()
{
readint(K);
readint(C);
readint(M);
N=K+C;
START=N;
END=N+1;
SIZE=N+2;
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
readint(matrix[i][j]);
if(matrix[i][j]==0)matrix[i][j]=INF;
}
}

int max_path=floyd_warshall();
int r=solve(1,max_path);
printf("%d\n",r);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: