链接:http://poj.org/problem?id=2391
题意:
有n个点,m条边(无向边),先输入n个点的信息,前面那个是这个点内已经有的牛,后面的是这个点最多可以容纳几头牛。m条边就是起点,终点,所需时间。问:所有奶牛都在点内安排好,所需的最少时间。如果无解输出-1。
根据题意,我们会想到一个思路,就是二分最大距离,然后跑最大流,这是一个初级思路,我写了这个之后发现是错的,仔细思考以后发现这样一种情况。不同的点间接连接着,我们二分的最大距离是x的话,这些点的距离最大确实都不超过x,但是加起来却超过了x,这样不符合我们的要求。我看了别人的博客,学习到一个思路就是拆点。
把每个点拆成入点和出点两种。那么我们在建图的时候,可以这样建图。
源点->每个点的入点 权值为这个点已存在的牛。
每个点的出点->汇点 权值为这个点可以容纳的牛。
每个点的入点->自己的出点 权值为所有牛的总数,因为每条路可以容纳无数牛。
最关键的是点与点之间的路径怎么建立。我们的目的是为了避免间接相连,也就是说,每条路径存的都要是直达。从前面的边可以看出,从每个点的出点出去之后都是汇点,而且,每个点的入点都是从源点得到的。所以要直达的话,点之间的路径就是符合条件的边(u,v)的(u)入点->(v)出点。
知道这些条件以后,就是二分距离,然后最大流了。
这题还有一个地方需要注意,就是一开始在图中设置的距离的最大值的问题,我们考虑有200个点,每个点 i 只和i + 1相连,而且距离是最大值1e9,那么点 1 和点200的距离就是199*1e9,差不多200*1e9就是2e11。因为一开始最大值设置的不对,一直错没有发现原因。
Accepted 1708K 282MS G++ 2850B
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<cctype>
#include<set>
#include<cassert>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=1e9+7;
typedef pair<int,int> pii;
#define in(x) (x)
#define out(x) (x+n)
struct node{
int cow,last;
}val[210];
int n,m,Cow,st,ed;
ll pic[210][210];
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(pic[i][j]>pic[i][k]+pic[k][j]){
pic[i][j]=pic[i][k]+pic[k][j];
}
}
}
}
}
int F[410][410];
int d[410];
void build(ll v){
st=0;ed=n+n+1;
memset(F,0,sizeof F);
for(int i=1;i<=n;i++){
F[st][in(i)]=val[i].cow;
F[out(i)][ed]=val[i].last;
F[in(i)][out(i)]=Cow;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(pic[i][j]<=v){
F[in(i)][out(j)]=Cow;
}
}
}
}
bool BFS(){
queue<int> Q;
memset(d,-1,sizeof d);
d[st]=0;Q.push(st);
while(!Q.empty()){
int s=Q.front();Q.pop();
for(int i=1;i<=ed;i++){
if(F[s][i]>0&&d[i]<0){
d[i]=d[s]+1;Q.push(i);
}
}
}
return d[ed]>0;
}
int DFS(int s,int t,int flow){
if(s==t||flow==0)return flow;
int ans=0;
for(int i=1;i<=ed;i++){
if(F[s][i]>0&&d[i]==d[s]+1){
int ff=DFS(i,t,min(flow,F[s][i]));
if(ff>0){
F[s][i]-=ff;
F[i][s]+=ff;
ans+=ff;
flow-=ff;
if(!flow)break;
}
}
}
if(!ans)d[s]=-1;
return ans;
}
int dinic(ll v){
build(v);
int ans=0;
while(BFS()){
ans+=DFS(st,ed,INF);
}
return ans;
}
int main(){
// freopen("D://input.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&val[i].cow,&val[i].last);
Cow+=val[i].cow;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j)pic[i][j]=2e11;
else pic[i][j]=0;
}
}
for(int i=1;i<=m;i++){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(pic[a][b]>c)pic[a][b]=pic[b][a]=c;
}
floyd();
ll l=0,r=0,ans=-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(pic[i][j]!=2e11)
r=max(r,pic[i][j]);
}
}
while(l<=r){
ll m=(l+r)>>1;
if(dinic(m)==Cow){
ans=m;r=m-1;
}
else l=m+1;
}
printf("%I64d\n",ans);
return 0;
}