有N块田,每块田下雨时可以容纳a[i]头牛,每块田现在有b[i]头牛,给出一些田与田之间的无向路径及距离,问下雨时最少多少时间后所有牛都能到避雨的地方。
首先floyd求出任意两点的最短距离,然后二分时间,加进去小于时间的边
建图,左边的点代表牛,右边的点代表田地,每一条流表示,一头牛进入了哪一个田地。
真练debug能力啊
1.位运算,运算等级太低,必须加(),毕竟多加不会错,小心驶得万年船啊
2.搞两个inf,有不同的用途
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<iostream>
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long ll;
const int inf=1<<29;
const ll INF=1ll<<59;
const int N=205;
struct aa
{
int pre,to,cap,flow;
}edge[N*N*2];
int head[N*2],tot;//edge
int n,p,now[N],can[N];//information
ll a[N][N],ans;//map
int lev[N*3],s,t;//dinic
void addedge(int x,int y,int z)
{
edge[++tot].to=y;edge[tot].pre=head[x];edge[tot].cap=z;head[x]=tot;
edge[++tot].to=x;edge[tot].pre=head[y];edge[tot].cap=0;head[y]=tot;
}
bool bfs()
{
memset(lev,0,sizeof(lev));
lev[s]=1;queue<int> q;q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for (int i=head[u];i;i=edge[i].pre)
if (edge[i].cap>edge[i].flow&&!lev[edge[i].to])
{
lev[edge[i].to]=lev[u]+1;
if (edge[i].to==t) return true;
q.push(edge[i].to);
}
}
return false;
}
int dfs(int u,int maxflow)
{
if (u==t||maxflow==0) return maxflow;
int ans=0;
for (int i=head[u];i;i=edge[i].pre)
if (lev[edge[i].to]==lev[u]+1)
{
int flow=dfs(edge[i].to,min(edge[i].cap-edge[i].flow,maxflow));
ans+=flow;
maxflow-=flow;
edge[i].flow+=flow;
edge[((i-1)^1)+1].flow-=flow;
//异或的外面必须加括号,调了一上午。。,异或等位运算的优先级太低,必需注意括号的问题 !!!!!!!
if(maxflow==0) return ans;
}
return ans;
}
int work(ll limit)//每一次运行,重新加边
{
int ans=0;
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
tot=0;s=0,t=n*2+1;
for (int i=1;i<=n;i++) addedge(s,i,now[i]),addedge(i+n,t,can[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a[i][j]<=limit) addedge(i,j+n,inf);
while (bfs()) ans+=dfs(s,inf);
return ans;
}
int main()
{
scanf("%d%d",&n,&p);
int x,y,total=0;ll z;
for (int i=1;i<=n;i++) scanf("%d%d",&now[i],&can[i]),total+=now[i];
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++) a[i][j]=a[j][i]=INF;//初始化
for (int i=1;i<=p;i++)
{
scanf("%d%d%lld",&x,&y,&z);
if(z<a[x][y]) a[x][y]=a[y][x]=z;
}
ll r=0;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (a[i][j]>a[i][k]+a[k][j])a[i][j]=a[i][k]+a[k][j];
if (r<a[i][j]&&a[i][j]!=INF)r=a[i][j];//这个地方绝不能等于INF????为什么
}
ll l=0,mid;ans=-1;r++;
while (l<r)
{
mid=(l+r)>>1;
if (work(mid)<total) l=mid+1;
else ans=r=mid;
}
printf("%lld\n",ans);
return 0;
}
总结:
这题的建图还是很显然的,关键是问最小时间,要保证满流,由此分析就可以二分时间,以二分的时间为限制加边,跑网络流。//这里的网络流就用来判定的