• jzoj 1287. 躲雨


    Question

    给你nn个点,mm条边。每个点都有一个容量限制和当前存在的量,每条边都有一个所需时间。
    求当所有点的量都符合限制是的最少需要时间。

    Solution

    我们先用floydfloyd求出两两点之间的最短时间。
    然后二分答案,对于时间<=mid<=mid的边就加,而后跑一遍网络流看看是否全都能流完即可。
    加边具体操作:
    设起始点为SS,终点为TT
    1.SS向第ii个点连一条a[i]a[i]的边
    2.第n+in+i个点向TT连一条b[i]b[i]的边
    3.对于时间<=mid<=mid的原边(i,n+i)(i,n+i),第ii个点向第n+in+i个点连一条a[i]a[i]的边

    Code

    #include<cstdio>
    #include<cstring>
    #define N 210
    #define ll long long
    using namespace std;
    struct node{int v,fr,flow;}e[N*N*20];
    int n,m,a[N],b[N],tail[N<<1],cnt;
    int S=0,T,num=0,dis[N<<1],gap[N<<1];
    ll l=0,r=0,mid,ans=-1,fl[N][N];
    
    inline int read()
    {
    	int x=0; char c=getchar();
    	while (c<'0' || c>'9') c=getchar();
    	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    
    inline ll min(ll x,ll y) {return x<y ? x:y;}
    
    inline void add(int u,int v,int flow)
    {
    	e[++cnt]=(node){v,tail[u],flow}; tail[u]=cnt;
    	e[++cnt]=(node){u,tail[v],0}; tail[v]=cnt;
    }
    
    int dfs(int x,int hav)
    {
    	if (x==T) return hav;
    	int gone=0;
    	for (int p=tail[x],v,can;p;p=e[p].fr)
    	{
    		v=e[p].v;
    		if (dis[v]+1!=dis[x] || !e[p].flow) continue;
    		can=dfs(v,min(hav-gone,e[p].flow));
    		e[p].flow-=can,e[p^1].flow+=can,gone+=can;
    		if (gone==hav) return gone;
    	}
    	gap[dis[x]]--;
    	if (!gap[dis[x]]) dis[S]=T;
    	gap[++dis[x]]++;
    	return gone;
    }
    
    bool check(ll mid)
    {
    	cnt=1;
    	memset(tail,0,sizeof(tail));
    	memset(dis,0,sizeof(dis));
    	memset(gap,0,sizeof(gap));
    	for (int i=1;i<=n;i++)
    		for (int j=i+1;j<=n;j++)
    			if (fl[i][j]<=mid) 
    				add(i,n+j,a[i]),add(j,n+i,a[j]);
    	for (int i=1;i<=n;i++)
    		add(S,i,a[i]),add(n+i,T,b[i]),add(i,n+i,a[i]);
    	int s=0;
    	while (dis[S]<T) s+=dfs(S,num);
    	if (s==num) return 1;
    	else return 0;
    }
    
    int main()
    {
    	freopen("rain.in","r",stdin);
    	freopen("rain.out","w",stdout);
    	n=read(),m=read();T=n+n+1;
    	for (int i=1;i<=n;i++)
    		a[i]=read(),b[i]=read(),num+=a[i];
    	memset(fl,60,sizeof(fl));
    	for (int i=1,u,v,lg;i<=m;i++)
    	{
    		u=read(),v=read(),lg=read();r+=lg;
    		fl[v][u]=fl[u][v]=min(fl[u][v],lg);
    	}
    	for (int k=1;k<=n;k++)
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++)
    				fl[j][i]=fl[i][j]=min(fl[i][j],fl[i][k]+fl[k][j]);
    	while (l<=r)
    	{
    		mid=l+r>>1;
    		if (check(mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    NCPC2016
    2016 ACM-ICPC CHINA-Final
    2016沈阳区域赛题解
    NAIPC2016部分题解
    Gym
    数论之莫比乌斯反演
    2018 多校 HDU
    LightOJ
    LightOJ
    java操作XML---XML基础知识
  • 原文地址:https://www.cnblogs.com/jz929/p/11817518.html
Copyright © 2020-2023  润新知