• 【NOI2008T3】志愿者招募-线性规划+最小费用最大流


    测试地址:志愿者招募

    做法:根据这位大牛的方法做的,看完之后觉得这题简直是神题啊!能想出来也是太强了。

    好了废话不多说,这位大牛说的构图原理是非常清楚的,就是利用线性规划建立等式,化成只有一边为0的形式,然后把正的量看成流入的流量,把负的量看成流出的流量,就可以满足流量平衡,然后按照这些东西连边即可。

    然而我们大可不必在程序里面把这些式子都推出来再建图,实际上我们可以发现,若把0和n+2看成附加源点和附加汇点,1~n+1看成上文中说的那些式子代表的顶点,我们可以发现规律:如果有一类志愿者从第a天到第b天工作,工资是c,那么根据推演之后一定是从顶点a到顶点b+1之间连一条容量无限,费用为c的边。这一步是连上了正负X变量所代表的边。下一步连正负Y变量所代表的边,可知就是在2到1,3到2,...,n+1到n之间连接一条容量无限,费用为0的边。唯一要算的就是上面这些式子的常数项,然后按文中的方法连接附加源点和附加汇点的边即可。最后对这个网络做一遍最小费用最大流,最小费用就是答案。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #define inf 1000000000
    using namespace std;
    int n,m,p[1010][1010]={0},v[1010]={0},vp[1010];
    int tot=1,first[1010]={0},dis[1010],maxf[1010],last[1010],laste[1010];
    bool vis[1010];
    struct edge {int v,f,c,next;} e[100010];
    
    void insert(int a,int b,int f,int c)
    {
      e[++tot].v=b,e[tot].f=f,e[tot].c=c,e[tot].next=first[a],first[a]=tot;
      e[++tot].v=a,e[tot].f=0,e[tot].c=-c,e[tot].next=first[b],first[b]=tot;
    }
    
    bool spfa()
    {
      queue<int> q;
      for(int i=0;i<=n+2;i++)
        dis[i]=inf,maxf[i]=inf;
      memset(vis,0,sizeof(vis));
      dis[0]=0;vis[0]=0;
      q.push(0);
      
      while(!q.empty())
      {
        int v=q.front();q.pop();
    	for(int i=first[v];i;i=e[i].next)
    	{
    	  if (e[i].f)
    	  {
    	    if (dis[e[i].v]>dis[v]+e[i].c)
    		{
    		  dis[e[i].v]=dis[v]+e[i].c;
    		  maxf[e[i].v]=min(maxf[v],e[i].f);
    		  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[n+2]!=inf;
    }
    
    int mincost()
    {
      int cost=0;
      while(spfa())
      {
        cost+=maxf[n+2]*dis[n+2];
    	int v=n+2;
    	while(v)
    	{
    	  e[laste[v]].f-=maxf[n+2];
    	  e[laste[v]^1].f+=maxf[n+2];
    	  v=last[v];
    	}
      }
      return cost;
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
      for(int i=1,a,b,c;i<=m;i++)
      {
        scanf("%d%d%d",&a,&b,&c);
    	insert(a,b+1,inf,c);
      }
      for(int i=2;i<=n+1;i++)
        insert(i,i-1,inf,0);
      for(int i=n+1;i>=1;i--)
      {
        vp[i]=v[i]-v[i-1];
    	if (vp[i]>=0) insert(0,i,vp[i],0);
    	else insert(i,n+2,-vp[i],0);
      }
      
      printf("%d",mincost());
      
      return 0;
    }
    


  • 相关阅读:
    【索引】SyntaxHighlighter 使用参考
    【索引】博客心得
    SyntaxHighlighter 使用参考(一) 概述
    PEGA 十合一吉他控制器连接电脑玩《吉他英雄3》
    从SourceForge上获取CVS管理的开源代码
    从SourceForge上获取SVN管理的开源代码
    整数哈希介绍
    回文时间
    D2js 是如何处理并发的
    Windows 安装JRuby 生成 war 到 tomcat 运行
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793829.html
Copyright © 2020-2023  润新知