#网络流,费用流,SLF优化,SPFA,zkw费用流#jzoj 1586 codevs 1362 洛谷 2604 网络扩容

题目

有两个问题,首先求1到 n n n的最大流(不解释了),然后求1到n使最大流扩展 k k k的费用,每扩展一个最大流,扩展一次边的费用


分析

当然如何做第二个问题,可以重新建一个汇点流量是最大流 + k +k +k,费用为0,并且原来的边再建一次从 u u u v v v,费用为该边的费用,流量无限跑一次最大流,then就讲完了


代码

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define rr register
    using namespace std;
    struct node{int y,w,f,next;}e[20005];
    int n,k=1,dis[1003],ls[1003],ans; bool v[1003];
    inline int in(){
    	rr int ans=0; rr char c=getchar();
    	while (c<48||c>57) c=getchar();
    	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
    	return ans;
    }
    inline void add(int x,int y,int w,int f){
    	e[++k]=(node){y,w,f,ls[x]}; ls[x]=k;
    	e[++k]=(node){x,0,-f,ls[y]}; ls[y]=k;
    }
    inline int spfa(){//反向跑spfa
    	memset(v,0,sizeof(v)); memset(dis,127/3,sizeof(dis));
    	dis[n]=0; v[n]=1; rr deque<int>q; q.push_back(n);
    	while (q.size()){
    		rr int x=q.front(); q.pop_front();
            for (rr int i=ls[x];i;i=e[i].next)
            if (e[i^1].w&&dis[e[i].y]>dis[x]-e[i].f){
                dis[e[i].y]=dis[x]-e[i].f;
                if (!v[e[i].y]){
                    v[e[i].y]=1;
                    if (q.size()&&dis[e[i].y]<dis[q.front()]) q.push_front(e[i].y); else q.push_back(e[i].y);
                }
            }
            v[x]=0;
    	}
    	return dis[n+1]<707406378;
    }
    inline int dfs(int x,int now){//长得很像dinic
        if (x==n) {v[n]=1; return now;}
        rr int rest=0,f; v[x]=1;
        for (rr int i=ls[x];i;i=e[i].next)
        if (!v[e[i].y]&&e[i].w>0&&dis[e[i].y]+e[i].f==dis[x]){
            rest+=(f=dfs(e[i].y,min(e[i].w,now-rest)));
            if (f) ans+=e[i].f*f,e[i].w-=f,e[i^1].w+=f;
            if (now==rest) return now;
        }
        return rest;
    }
    inline int zkw(){
    	int ans=0;
    	while (spfa()){
    		do{
    			memset(v,0,sizeof(v));
    			ans+=dfs(n+1,1e9);
    		}while (v[n]);
    	}
    	return ans;
    }
    int main(){
    	n=in(); rr int m=in(),t=in();
    	rr int w[m+1],f[m+1],t1;
    	for (rr int i=1;i<=m;i++){
    		rr int x=in(),y=in();
    		w[i]=in(); f[i]=in();
    		add(x,y,w[i],0);
    	}
    	add(n+1,1,2333333,0);
    	printf("%d ",t1=zkw()); t+=t1;
    	e[k].w=0; e[k^1].w=t;//超级源点
    	for (rr int i=1;i<=m;i++) e[i<<1].w=w[i],e[i<<1|1].w=0;//重新建图
    	for (rr int i=1;i<=m;i++) add(e[i<<1|1].y,e[i<<1].y,23333333,f[i]);//无限流量
    	zkw(); return !printf("%d",ans);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
令牌桶算法是一种常见的限算法,它可以控制请求的速率,防止系统被过多的请求压垮。下面是Java实现令牌桶算法的步骤和代码逻辑: 1. 定义一个令牌桶类,包含以下属性: - 最后一次令牌发放时间 - 桶的容量 - 令牌生成速度 - 当前令牌数量 2. 实现一个获取令牌的方法,该方法会在每次请求到来时被调用,具体实现如下: - 计算当前令牌数量 - 判断当前令牌数量是否足够 - 如果令牌数量不足,则拒绝请求 - 如果令牌数量足够,则领取令牌,并执行业务逻辑 3. 使用ScheduledExecutorService定时生成令牌,具体实现如下: - 每隔一段时间生成一定数量的令牌 - 如果令牌数量超过桶的容量,则不再生成令牌 下面是Java实现令牌桶算法的代码逻辑: ``` @Slf4j public class TokensLimiter { private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); // 最后一次令牌发放时间 public long timeStamp = System.currentTimeMillis(); // 桶的容量 public int capacity = 10; // 令牌生成速度10/s public int rate = 10; // 当前令牌数量 public int tokens; public void acquire() { scheduledExecutorService.scheduleWithFixedDelay(() -> { long now = System.currentTimeMillis(); // 当前令牌数 tokens = Math.min(capacity, (int) (tokens + (now - timeStamp) * rate / 1000)); // 每隔0.5秒发送随机数量的请求 int permits = (int) (Math.random() * 9) + 1; log.info("请求令牌数:" + permits + ",当前令牌数:" + tokens); timeStamp = now; if (tokens < permits) { // 若不到令牌,拒绝 log.info("限了"); } else { // 还有令牌,领取令牌 tokens -= permits; log.info("剩余令牌=" + tokens); } }, 1000, 500, TimeUnit.MILLISECONDS); } public static void main(String[] args) { TokensLimiter tokensLimiter = new TokensLimiter(); tokensLimiter.acquire(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值