• BZOJ 1927: [Sdoi2010]星际竞速(费用流)


    传送门

    解题思路

      仿照最小路径覆盖问题,用费用流解决此题。最小路径覆盖问题是拆点连边后用(n-)最大匹配,这里的话也是将每个点拆点,源点向入点连流量为(1),费用为(0)的边,向出点连流量为(1),费用为(a[i])的边,出点向汇点连流量为(1),费用为(0)的边。然后对于每条边,由(x)的入点向(y)的出点连流量为(1),费用为路径长度的边。跑一遍费用流。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    const int MAXN = 1605;
    const int MAXM = 20005;
    const int inf = 0x3f3f3f3f;
    typedef long long LL;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    
    inline int min(int x,int y){
    	return x<y?x:y;
    }
    
    int n,m,a[MAXN],head[MAXN],to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cost[MAXM<<1];
    int S,T,cnt=1,incf[MAXN],pre[MAXN],dis[MAXN];
    LL ans;
    bool vis[MAXN];
    queue<int> Q;
    
    inline void add(int bg,int ed,int w,int z){
    	to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=w,cost[cnt]=z,head[bg]=cnt;
    }
    
    inline bool spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,false,sizeof(vis));
    	while(Q.size()) Q.pop();
    	dis[S]=0;vis[S]=1;Q.push(S);incf[S]=inf;
    	while(Q.size()){
    		int x=Q.front();Q.pop();vis[x]=0;
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(dis[x]+cost[i]<dis[u] && val[i]){
    				dis[u]=dis[x]+cost[i];
    				incf[u]=min(incf[x],val[i]);
    				pre[u]=i;
    				if(!vis[u]) vis[u]=1,Q.push(u);
    			}
    		}
    	}
    	return (dis[T]==inf)?0:1;	
    }
    
    inline void update(){
    	int x=T,i;
    	while(x!=S){
    		i=pre[x];
    		val[i]-=incf[T];
    		val[i^1]+=incf[T];
    		x=to[i^1];
    	}
    	ans+=(LL)incf[T]*dis[T];
    }
    
    int main(){
    	n=rd(),m=rd();int x,y,z;S=2*n+1,T=2*n+2;
    	for(int i=1;i<=n;i++) a[i]=rd();
    	for(int i=1;i<=n;i++){
    		add(S,i,1,0),add(i,S,0,0);
    		add(S,i+n,1,a[i]),add(i+n,S,0,-a[i]);
    		add(i+n,T,1,0),add(T,i+n,0,0);
    	}
    	for(int i=1;i<=m;i++){
    		x=rd(),y=rd(),z=rd();if(x>y) swap(x,y);
    		add(x,y+n,1,z),add(y+n,x,0,-z);
    	}
    	while(spfa()) update();
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [转载]重构代码的7个阶段
    查看JDK源码
    敏捷结果30天之第七天:设定边界值和缓冲
    敏捷结果30天之第十一天:高效能、慢生活
    他们到底需要神马???——戏说“用户需求”
    敏捷结果30天之第一天:总体认识敏捷结果方法
    敏捷结果30天之第五天:使用热图标识出重要事情
    重构代码学习笔记一:重构的原则
    开发可统计单词个数的Android驱动程序(2)
    使用Android NDK和Java测试Linux驱动
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10117957.html
Copyright © 2020-2023  润新知