• P3980 [NOI2008]志愿者招募


    题解

    发现就是一个线性规划。
    我们用 (x_i) 来表示第 (i) 种志愿者的个数, (a_i) 来表示每一天的人数下限。

    [x_o+x_p+...ge a_i\ x_o+x_q+...ge a_{i+1}\ ... ]

    就套路一下,把不等号变成等号。

    [x_o+x_p+...=a_i+c_i\ x_o+x_q+...=a_{i+1}+c_{i+1} ]

    然后可以做一下差,然后发现每一个 (x_o) 只会在等式的左右各出现一次,分别是 (s_a)(t_a+1) 的位置。然后 (c_i) 也是只出现一次,然后就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1e3+5,M=1e4+5;
    const int INF=1e18+7;
    int n,m,from,to,tot=0;
    int id[N],a[N];
    struct Vol{int s,t,c;}b[M];
    struct Edge{int nxt,to,flow,cost;};vector<Edge> e;int fir[N];
    void add(int u,int v,int x,int y){e.push_back((Edge){fir[u],v,x,y}),fir[u]=e.size()-1;}
    int dis[N],cur[N],res=0;
    queue<int> q;bool vis[N];
    bool spfa(){
    	for(int i=1;i<=tot;++i) dis[i]=INF,cur[i]=fir[i];
    	dis[from]=0,vis[from]=true,q.push(from);
    	while(!q.empty()){
    		int u=q.front();vis[u]=false,q.pop();
    		// printf("%d %d %d
    ",u,dis[u],fir[u]);
    		for(int i=fir[u];i>=0;i=e[i].nxt){
    			// printf("---%d %d %d
    ",e[i].to,e[i].cost,dis[e[i].to]);
    			if(!e[i].flow||dis[e[i].to]<=dis[u]+e[i].cost) continue;
    			dis[e[i].to]=dis[u]+e[i].cost;
    			if(!vis[e[i].to]) vis[e[i].to]=true,q.push(e[i].to);
    		}
    	}
    	return dis[to]!=INF;
    }
    int dfs(int u,int flow){
    	if(u==to) return flow;
    	int res=0;vis[u]=true;
    	for(int i=cur[u];i>=0&&flow;i=e[i].nxt){
    		int v=e[i].to;cur[u]=i;
    		if(!e[i].flow||dis[e[i].to]!=dis[u]+e[i].cost||vis[v]) continue;
    		int tmp=dfs(e[i].to,min(flow,e[i].flow));
    		e[i].flow-=tmp,e[i^1].flow+=tmp,flow-=tmp,res+=tmp;
    	}
    	return vis[u]=false,res;
    }
    signed main(){
    	cin>>n>>m;
    	from=++tot,to=++tot;
    	memset(fir,-1,sizeof(fir)),id[n+1]=++tot;
    	for(int i=1;i<=n;++i) scanf("%lld",&a[i]),id[i]=++tot;
    	for(int i=1;i<=m;++i) scanf("%lld%lld%lld",&b[i].s,&b[i].t,&b[i].c);
    	for(int i=1;i<=n;++i){
    		add(from,id[i+1],a[i],0),add(id[i+1],from,0,0);
    		add(id[i],to,a[i],0),add(to,id[i],0,0);
    		add(id[i],id[i+1],INF,0),add(id[i+1],id[i],0,0);
    	}
    	for(int i=1;i<=m;++i){
    		add(id[b[i].t+1],id[b[i].s],INF,b[i].c);
    		add(id[b[i].s],id[b[i].t+1],0,-b[i].c);
    	}
    	while(spfa()) res+=dis[to]*dfs(from,INF);
    	printf("%lld
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    类方法代码重构寻找坏味道
    迭代二分查找二分查找
    系统牛逼[置顶] 使用RAMP理解内在动机 Understanding Intrinsic Motivation with RAMP
    对象服务器Webservices获取天气
    手机服务器Android消息推送(二)基于MQTT协议实现的推送功能
    概率小数2013年阿里巴巴暑期实习招聘笔试题目(不完整,笔试时间:2013.5.5)
    像素颜色JavaFX示例简易图片处理工具
    算法队列SPFA算法详解
    选择文件Eclipse制作jar包
    nullnull推箱子
  • 原文地址:https://www.cnblogs.com/Point-King/p/14353774.html
Copyright © 2020-2023  润新知