zoukankan      html  css  js  c++  java
  • 【HDU3488】Tour-最小费用最大流

    测试地址:Tour

    题目大意:在有N个点,M条有向边的有向图中找到若干个环,并使得每个点都在且只在其中一个环上,并使得环上的权值之和最小,输出这个最小值,如果不存在合法方案输出-1。

    做法:这个转化方法十分神奇,我们把一个点拆成两个点,一个点连接出边,一个点连接入边,构成一个二分图,可以证明任何一个该二分图的完美匹配都对应着一个选择环的合法策略(前提是一个点拆成的两点间无边相连),那么问题就是求权值最小的完美匹配了,那么做法就很显然了,可以用KM算法做,而且更快,但是鉴于本人是想练习最小费用最大流,所以写了一个最小费用最大流的解法,920ms,不注意常数可能会爆......

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    int T,n,m,first[510],tot,ans,dis[510],last[510],laste[510];
    struct {int v,c,f,next;} e[200010];
    bool vis[510]={0};
    
    void insert(int a,int b,int c,int f)
    {
      e[++tot].v=b;
      e[tot].c=c;
      e[tot].f=f;
      e[tot].next=first[a];
      first[a]=tot;
    }
    
    bool spfa(int s)
    {
      int t=2*n+1;
      memset(dis,-1,sizeof(dis));
      queue<int> q;
      q.push(s);vis[0]=1;dis[0]=0;
      while(!q.empty())
      {
        int v=q.front();q.pop();
    	for(int i=first[v];i;i=e[i].next)
    	  if (e[i].f&&(dis[e[i].v]==-1||dis[v]+e[i].c<dis[e[i].v]))
    	  {
    	    dis[e[i].v]=dis[v]+e[i].c;
    		last[e[i].v]=v;
    		laste[e[i].v]=i;
    		if (!vis[e[i].v]) {vis[e[i].v]=1;q.push(e[i].v);}
    	  }
    	vis[v]=0;
      }
      return dis[t]!=-1;
    }
    
    int mincost()
    {
      int maxf=0,ans=0;
      while(spfa(0))
      {
        ans+=dis[2*n+1];
        maxf++;
    	int v=2*n+1;
    	while(v)
    	{
    	  e[laste[v]].f--;
    	  e[laste[v]^1].f++;
    	  v=last[v];
    	}
      }
      if (maxf<n) return -1;
      else return ans;
    }
    
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
        tot=1;
    	memset(first,0,sizeof(first));
    	
        scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    	  insert(0,i,0,1);insert(i,0,0,0);
    	  insert(n+i,2*n+1,0,1);insert(2*n+1,n+i,0,0);
    	}
    	
    	for(int i=1,a,b,c;i<=m;i++)
    	{
    	  scanf("%d%d%d",&a,&b,&c);
    	  if (a!=b) insert(a,n+b,c,1);insert(n+b,a,-c,0);
    	}
    	
    	printf("%d
    ",mincost());
      }
      
      return 0;
    }
    


  • 相关阅读:
    Qt 之 emit、signals、slot的使用
    qt中的 connect 函数
    进程同步:生产者消费者模型 以及解决方法
    Linux 时间 与 定时器
    Linux 环境编程:errno的基本用法
    Linux 环境编程:dirfd参数 有关解析
    Kubernetes设计理念
    禅道升级
    关闭自动更新
    linux下的特殊模式
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793749.html
Copyright © 2011-2022 走看看