zoukankan      html  css  js  c++  java
  • BZOJ.1927.[SDOI2010]星际竞速(无源汇上下界费用流SPFA /最小路径覆盖)

    题目链接
    上下界费用流:

    /*
    每个点i恰好(最少+最多)经过一次->拆点(最多)+限制流量下界(i,i',[1,1],0)(最少) 
    然后无源汇可行流 不需要源汇。
    
    注: SS只会连i',求SS->TT的最大流 该走的i->i'是不会不走的 
    */
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define gc() getchar()
    const int N=850<<1,M=20000,INF=0x3f3f3f3f;
    
    int n,m,A[N],src,des,Enum,H[N],fr[M<<1],to[M<<1],nxt[M<<1],cap[M<<1],cost[M<<1];
    int dis[N],pre[N];
    bool inq[N];
    std::queue<int> q;
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    inline void AddEdge(int u,int v,int w,int c)
    {
    	to[++Enum]=v, nxt[Enum]=H[u], fr[Enum]=u, cap[Enum]=w, cost[Enum]=c, H[u]=Enum;
    	to[++Enum]=u, nxt[Enum]=H[v], fr[Enum]=v, cap[Enum]=0, cost[Enum]=-c, H[v]=Enum;
    }
    bool SPFA()
    {
    	memset(dis,0x3f,sizeof dis);
    	dis[src]=0, q.push(src);
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		inq[x]=0;
    		for(int i=H[x];i;i=nxt[i])
    			if(cap[i] && dis[to[i]]>dis[x]+cost[i])
    			{
    				dis[to[i]]=dis[x]+cost[i], pre[to[i]]=i;
    				if(!inq[to[i]]) inq[to[i]]=1, q.push(to[i]);
    			}
    	}
    	return dis[des]<INF;
    }
    int MCMF()
    {
    	int mn=INF,res=0;
    	for(int i=des;i!=src;i=fr[pre[i]])
    		mn=std::min(mn,cap[pre[i]]);
    	for(int i=des;i!=src;i=fr[pre[i]])
    		cap[pre[i]]-=mn,cap[pre[i]^1]+=mn,res+=mn*cost[pre[i]];
    	return res;
    }
    
    int main()
    {
    	Enum=1;
    	n=read(),m=read();int p=n<<1|1/*中转*/,ss=0,tt=n*2+2;
    	for(int i=1;i<=n;++i)
    	{
    		AddEdge(p,i,1,read()), AddEdge(i+n,p,1,0);
    //		AddEdge(i,i+n,0,0),//下界-上界后 边cap为0,有没有一样了 
    		AddEdge(ss,i+n,1,0), AddEdge(i,tt,1,0);
    	}
    	for(int u,v,w,i=1;i<=m;++i)
    	{
    		u=read(),v=read(),w=read();
    		if(u>v) std::swap(u,v);
    		if(u==v) continue;
    		AddEdge(u+n,v,1,w);
    	}
    	src=ss, des=tt;
    	int flow=0;
    	while(SPFA()) flow+=MCMF();
    	printf("%d",flow);
    
    	return 0;
    }
    
    

    最小路径覆盖:

    /*
    每个点可以跳到一个点->即每个点可以到S,再从S重新选择新一条路->好像最小路径覆盖 
    对一条路径u->v建边u->v'(->T),表示可以通过u到过v,但是一共只能经过u一次 
    移动可以直接S->u'(->T),cost=A[u],表示花费A[u]可以直接走过它 
    将每个点拆成i,i',连边S->i、i'->T,这样求最大流所有点一定都会经过一次 
    比上一种方法少2n条边 但比上个..慢些..
    cap都是1,优化下 更慢了==
    */
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define gc() getchar()
    const int N=850<<1,M=18000,INF=0x3f3f3f3f;
    
    int n,m,A[N],src,des,Enum,H[N],fr[M<<1],to[M<<1],nxt[M<<1],cap[M<<1],cost[M<<1];
    int dis[N],pre[N];
    bool inq[N];
    std::queue<int> q;
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    inline void AddEdge(int u,int v,int c)
    {
    	to[++Enum]=v, nxt[Enum]=H[u], fr[Enum]=u, cap[Enum]=1, cost[Enum]=c, H[u]=Enum;
    	to[++Enum]=u, nxt[Enum]=H[v], fr[Enum]=v, cap[Enum]=0, cost[Enum]=-c, H[v]=Enum;
    }
    bool SPFA()
    {
    	memset(dis,0x3f,sizeof dis);
    	dis[src]=0, q.push(src);
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		inq[x]=0;
    		for(int i=H[x];i;i=nxt[i])
    			if(cap[i] && dis[to[i]]>dis[x]+cost[i])
    			{
    				dis[to[i]]=dis[x]+cost[i], pre[to[i]]=i;
    				if(!inq[to[i]]) inq[to[i]]=1, q.push(to[i]);
    			}
    	}
    	return dis[des]<INF;
    }
    int MCMF()
    {
    	int res=0;
    //	for(int i=des;i!=src;i=fr[pre[i]])
    //		mn=std::min(mn,cap[pre[i]]);
    	for(int i=des;i!=src;i=fr[pre[i]])
    		cap[pre[i]]^=1,cap[pre[i]^1]^=1,res+=cost[pre[i]];
    	return res;
    }
    
    int main()
    {
    	Enum=1;
    	n=read(),m=read();
    	src=0, des=n<<1|1;
    	for(int i=1;i<=n;++i)
    		AddEdge(src,i+n,read()), AddEdge(src,i,0), AddEdge(i+n,des,0);
    	for(int u,v,w,i=1;i<=m;++i)
    	{
    		u=read(),v=read(),w=read();
    		if(u>v) std::swap(u,v);
    		if(u==v) continue;
    		AddEdge(u,v+n,w);
    	}
    	int flow=0;
    	while(SPFA()) flow+=MCMF();
    	printf("%d",flow);
    
    	return 0;
    }
    
  • 相关阅读:
    MT【139】公比为有理数
    鼠标右键怎么清除Catalyst Control Center
    人脸识别技术框架
    Qt生成灰度图(转载)
    人脸识别必读的N篇文章
    QT+vs2010下改变可执行程序的图标
    内部排序技术
    ubuntu下配置qt+opengl+opencv
    HOG算子
    基于HOG特征的Adaboost行人检测
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8422178.html
Copyright © 2011-2022 走看看