HDU 3667 Transportation 费用流巧妙拆边

题意:给n点,m条边,对于每条边为有向边,给容量和ai,那么这条边的费用就是:实际容量的平方乘以ai,问从1到n运送k单位物资的最小费用。


想法:费用不是线性,所以有的容量不必跑满,甚至是量这条路的最小容量也不用跑满,就像第三个数据,那么就要拆边,拆成容量为一的边,那么剩下的问题就是费用如何给的问题了,因为n^2=1+3+5+7+...+(2*n-1),所以分别给每条容量为一的边赋等式右边的费用就好了,建边是source向1连一条容量为k费用为0的边,n到sink连一条容量为inf费用为0的边。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x7fffffff
using namespace std;
const int nodes=100+50;
const int edges=155000;
struct node
{
    int u,v,flow,fee;
    int next;
}e[edges];
int n,m,k,s,t;
int head[nodes],cnt;
class Dinic
{
    public:
        int spfa()
        {
            memset(vis,0,sizeof(vis));
            memset(pe,-1,sizeof(pe));
            for(int i=s;i<=t;i++)
            dis[i]=inf;
            queue<int>q;
            while(!q.empty()) q.pop();
            dis[s]=0;
            vis[s]=1;
            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 result()
        {
            int res=0;
            int f=0;
            while(spfa())
            {
                int minflow=inf;
                for(int i=pe[t];i+1;i=pe[e[i].u])
                {
                    if(minflow>e[i].flow)
                    minflow=e[i].flow;
                }
                for(int i=pe[t];i+1;i=pe[e[i].u])
                {
                    e[i].flow-=minflow;
                    e[i^1].flow+=minflow;                
                }
                f+=minflow;
                res+=dis[t]*minflow;
            }
            if(f!=k) return -1;
            return res;
        }
    private:
        int dis[nodes],pe[nodes],vis[nodes];
}dinic;
void Init()
{
    memset(head,-1,sizeof(head));
    cnt=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++;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        Init(); 
        s=0;t=n+1;
        add(s,1,k,0);
        add(n,t,inf,0);
        for(int i=1;i<=m;i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            for(int j=1;j<=d;j++)
            {
                add(a,b,1,c*(2*j-1));
            }
        }
        int res=dinic.result();
        printf("%d\n",res);
    }
    return 0;
}

你可能感兴趣的:(HDU 3667 Transportation 费用流巧妙拆边)