HDU 4067 Random Maze 最小费用最大流(类似混合欧拉路)

原创 2015年11月20日 10:18:27

题意:给你一个Random Maze的定义,一个起点终点,起点终点的出入度关系,差1,其余的点出入度相等,现在给一个有向图,每一个边可以选择留还是删,费用分别是a,b。问你此图要是变成Random Maze所要的最小费用。


想法:类似于混合欧拉路的思想,对于每一给边,留还是删问题是关键。对于原图有一部分的费用是一定要出的那就是所有边的留删费用最少的费用和。如果由留变成删,或者删变成留,我们只需要额外支付转换的费用就好了,那么对于某条边来说:Max(a,b)-Min(a.b)。当a<=b的时候,选择留下,实际上是要连a->b这条边,但是不知道是否正真的对于全局来说要留下这条边,为了可以有机会转换,连接b->a这条边但是对于出入度的更新还是要以a->b为标准的。当a>b的时候,选择删掉,实际上是不连边了,但是为可有机会转换,连接a->b这条边,但是出入度不用更新,因为实际是不要这个边的。为了让所有的点的入读和初度一样,我们借助网络流,跑最大流,这里的流,我们是要跑满流的,因为要所有点的出度和入度多要相等,还有就是每一条边有一个费用,表示这条路的花费,即对之前的边是否要转换。很容易想到用费用流。

建图:1.虚拟source和sink;

2.a<=b b->a连接一条容量为1(这条边只可以改变一次初度入度关系),费用为b-a的边。跟新indegree,outdegree;

3.a>b a->b连接一条容量为1,费用为a-b的边;

4.给你的起点和终点的出入度定义的就不相等,所以起点的入度和终点的出度分别加1;

5.source向所有indegree>outdegree的点连一条容量为出入度差费用为0的边。

   解释:一个点v,他只需要增加indegree-outdegree的出度就可以达到出入度相等了,在之前建边时,如果建了一条v出去的边,这条边可能是要留下来的或是删除的边,如果是要留下来的边,那么它对v的入度有影响,这里可以表示这个边可能要删掉,通过增加他的出度,等价于减少它的入度。如果是要删除的边,这里表示,这条边可能不删除了,增加出度。

6.所有indegree<=outdegree向sink连一条容量为出入度差费用为0的边。


如果达到满流,表示可以构成Random Maze,输出费用流加上之前的固定值。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 0x7fffffff
using namespace std;
const int nodes=150;
const int edges=10000; 
int n,m,ss,tt,s,t,totfee,sum1,sum;
int in[nodes],out[nodes],head[nodes],cur[nodes],cnt;
struct node
{
	int u,v,next,fee,flow;
}e[edges];
class DINIC
{
    public:
        int spath()
        {
            queue<int>q;
            while(!q.empty()) q.pop();
            for(int i=s;i<=t;i++)
            dis[i]=inf;
            memset(vis,0,sizeof(vis));
            memset(pe,-1,sizeof(pe));
            vis[s]=1;
            dis[s]=0;
            q.push(s);
            while(!q.empty())
            {
                int u=q.front();
                q.pop();
                vis[u]=0;
                for(int i=head[u];i+1;i=e[i].next)
                {
                    int v=e[i].v;
                    if(dis[v]>dis[u]+e[i].fee&&e[i].flow>0)
                    {
                        dis[v]=dis[u]+e[i].fee;
                        pe[v]=i;
                        if(!vis[v])
                        {
                            vis[v]=1;
                            q.push(v);
                        }
                    }
                }
            }
            return dis[t]!=inf;
        }
        int Min(int a,int b)
        {
            if(a<b) return a;
            return b;
        }
        int dfs(int u,int flow)
        {
            int cost=0;
            if(u==t)
            {
                totfee+=dis[t];
                return flow;
            }
            for(int i=head[u];i+1;i=e[i].next)
            {
                int v=e[i].v;
                if(pe[v]==i&&e[i].flow>0)
                {
                    int min=dfs(v,Min(e[i].flow,flow-cost));
                    if(min>0)
                    {
                        e[i].flow-=min;
                        e[i^1].flow+=min;
                        cost+=min;
                        if(cost==flow) break;
                    }
                    else pe[v]=-1;
                }
            }
            return cost;
        }
        int result()
        {
        	int ans=0;
            while(spath())
            {
                ans+=dfs(s,inf);
            }
            return ans;
        }
    private:
        int dis[nodes],vis[nodes],pe[nodes];        
}dinic;
void Init()
{
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	memset(head,-1,sizeof(head));
	cnt=totfee=0;
	sum1=sum=0;
}
void add(int a,int b,int flow,int fee)
{
	e[cnt].u=a;
	e[cnt].v=b;
	e[cnt].flow=flow;
	e[cnt].fee=fee;
	e[cnt].next=head[a];
	head[a]=cnt++;
	
	e[cnt].u=b;
	e[cnt].v=a;
	e[cnt].flow=0;
	e[cnt].fee=-fee;
	e[cnt].next=head[b];
	head[b]=cnt++;
}
void judge()
{
	int res=dinic.result();
	if(res!=sum1||totfee==0) 
	{
		printf("impossible\n");
		return;
	}
	printf("%d\n",sum+totfee);
}
int main()
{
	int tesk,ca=1;
	scanf("%d",&tesk);
	while(tesk--)
	{
		scanf("%d%d%d%d",&n,&m,&ss,&tt);
		Init();
		for(int i=1;i<=m;i++)
		{
			int u,v,a,b;
			scanf("%d%d%d%d",&u,&v,&a,&b);
			if(a<=b)
			{//要这条边 
				sum+=a;
				add(v,u,1,b-a);
				out[u]++;in[v]++;
			}
			else 
			{//不要这条边
				sum+=b;
				add(u,v,1,a-b);
			}
		}
		in[ss]++;out[tt]++;
		s=0;t=n+1;
		for(int i=1;i<=n;i++)
		{
			if(in[i]>out[i]) 
			{
				add(s,i,in[i]-out[i],0);
				sum1+=in[i]-out[i];
			}
			else add(i,t,out[i]-in[i],0);
		}
		printf("Case %d: ",ca++);
		judge();
	}
	return 0;
} 


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

hdu 4067 最小费用最大流

/* 题意:给出一个有n个点m条边的有向图,现在要从图中删去一些边使得图满足以下条件: 1.图中只有一个入口(s)和一个出口(t) 2.所以边都是单向的(这个原图已经保证了) 3.对入口(s)...

HDU4067 Random Maze 最小费用最大流 福州网络赛

Random Maze Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota...

HDU 4067 Random Maze (最小费用最大流)

#include #include #include #include #include #include #include #include #define inf 0x3f3f3f3f #def...

hdu 4067 Random Maze(最小费用最大流)

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T...
  • fp_hzq
  • fp_hzq
  • 2011年10月08日 16:05
  • 1626

HDU 4067 Random Maze 最小费用最大流

完全参考自: http://www.cnblogs.com/wally/archive/2013/08/29/3288898.html 建好图,套个模板就OK了。 code: #include us...

hdu 4067 Random Maze 最小费用最大流

题意: 给出n个点,m条边,入口s和出口t,对于每条边有两个值a,b,如果保留这条边需要花费;否则,移除这条边需要花费b。              题目要求用最小费用构造一个有向图满足以下条件: ...

hdu 4067 Random Maze(最小费用流)

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T...
  • WEYuLi
  • WEYuLi
  • 2014年01月13日 21:45
  • 624

Random Maze (hdu 4067 最小费用流 好题 贪心思想建图)

最小费用最大流,重在建图,好题!

HDU 4067 Random Maze 费用流

//author: CHC //First Edit Time: 2014-10-16 10:05 //Last Edit Time: 2014-10-16 11:16 #include #incl...
  • CHCXCHC
  • CHCXCHC
  • 2014年10月28日 16:15
  • 421

【HDU】 4067 Random Maze 费用流

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 4067 Random Maze 最小费用最大流(类似混合欧拉路)
举报原因:
原因补充:

(最多只允许输入30个字)