POJ 3680 最小费用最大流

这题来源:《算法竞赛经典入门-训练指南》中的367页:区间k覆盖问题。

思路:这题建图比较机智,我刚开始想到能建的图也就是离散化后两个端点连边,流量为1,费用为负的权值(因为求的是最大费用最大流),然后再加上源点和汇点,也就如此而已;但是这样建图样例第二和第四个不正确,因为中间没有联系的没连边,然后k就没用了。

原来最重要的连边是i和i+1之间的连边,流量为k,费用为0;为什么要连这些边呢,刚开始我也没想明白,后面才知道,因为有的端点之间你要让它们产生联系并且受制与k次,那么就得把这些点都连边,这样就有联系了嘛!

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
#define maxn 20005
struct
{
    int v,w,c,next,re;
    //re记录逆边的下标,c是费用,w是流量
} e[maxn];
int n,cnt;
int head[maxn],que[maxn*8],pre[maxn],dis[maxn];
bool vis[maxn];
void add(int u, int v, int w, int c)
{
    e[cnt].v=v,e[cnt].w=w,e[cnt].c=c;
    e[cnt].next=head[u];
    e[cnt].re=cnt+1,head[u]=cnt++;
    e[cnt].v=u,e[cnt].w=0,e[cnt].c=-c;
    e[cnt].next=head[v];
    e[cnt].re=cnt-1,head[v]=cnt++;
}
bool spfa()
{
    int i, l = 0, r = 1;
    for(i = 0; i <= n; i ++)
        dis[i] = INF,vis[i] = false;
    dis[0]=0,que[0]=0,vis[0]=true;
    while(l<r)
    {
        int u=que[l++];
        for(i=head[u];i!=-1;i=e[i].next)
        {
            int v = e[i].v;
            if(e[i].w&&dis[v]>dis[u]+e[i].c)
            {
                dis[v] = dis[u] + e[i].c;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    que[r++] = v;
                }
            }
        }
        vis[u] = false;
    }
    return dis[n]!=INF;
}
int change()
{
    int i,p,sum=INF,ans=0;
    for(i=n;i!=0;i=e[e[p].re].v)
    {//e[e[p].re].v为前向结点,不理解看add和spfa
        p=pre[i];//p为前向结点编号
        sum=min(sum,e[p].w);
    }
    for(i=n;i!=0;i=e[e[p].re].v)
    {
        p=pre[i];
        e[p].w-=sum;
        e[e[p].re].w+=sum;
        ans+=sum*e[p].c;//c记录的为单位流量费用,必须得乘以流量。
    }
    return ans;
}
int EK()
{
    int sum=0;
    while(spfa()) sum+=change();
    return sum;
}
void init()
{
    mem(head,-1),mem(pre,0),cnt=0;
}
struct abc
{
    int u,v,w;
}aa[405];
int main()
{
    //freopen("1.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        int N,K,i,j,x,y,tmp=0,a[402];
        map<int,int>Map;
        scanf("%d%d",&N,&K);
        for(i=0;i<N;i++)
        {
            scanf("%d%d%d",&aa[i].u,&aa[i].v,&aa[i].w);
            a[tmp++]=aa[i].u,a[tmp++]=aa[i].v;
        }
        sort(a,a+tmp);
        int k=unique(a,a+tmp)-a;
        for(i=0,tmp=0;i<k;i++)
            Map[a[i]]=++tmp;
        for(i=0;i<N;i++)
        {
            int u=Map[aa[i].u],v=Map[aa[i].v];
            add(u,v,1,-aa[i].w);
        }
        for(i=1;i<tmp;i++)
            add(i,i+1,K,0);
        n=tmp+1;
        add(0,1,K,0),add(tmp,n,K,0);
        printf("%d\n",-EK());
    }
    return 0;
}
时间: 2024-09-30 19:18:31

POJ 3680 最小费用最大流的相关文章

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

poj 2516 最小费用最大流

Language: Default Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 14334   Accepted: 4908 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (m

poj 2135(最小费用最大流)

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14730   Accepted: 5614 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

POJ - 2195 最小费用最大流

题意:每个人到每个房子一一对应,费用为曼哈顿距离,求最小的费用 题解:单源点汇点最小费用最大流,每个人和房子对于建边 #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #include<iomanip&

poj 2135 最小费用最大流初步

这个题的意思是农夫约翰要呆人参观他的农场, 刚开始从1开始走, 走到N后又返回1点, 两次不能走相同的路, 问农夫约翰走的最短的路是多少?? 我们可以用最小MCMF来解决这个问题, 对于图中的每一条边, 我们建立了两条流量为1, 费用为边权的边, 再增加一个源点和一个汇点, 源点指向1, 流量为2,费用为0, N指向汇点, 流量为2费用为0, 然后求出最小费用即可, 代码如下: #include <cstdio> #include <algorithm> #include <

POJ 3422 最小费用最大流

链接: http://poj.org/problem?id=3422 题解: 关键是如何处理"只能获取一次"的问题,为此可以为每个点创建伪点,由两条有向边相连.原始点到伪点连一条容量为1,权值为负分数的边:原始点到伪点连一条容量为无穷,权值为0的边.前者表示分数只能拿一次,后者表示第二次第三次--可以继续走这个点,但是不拿分数.负权是因为题目要求的是"最大费用".又因为最多走同一个点K次,所以此处的无穷大取K就行了. 代码: 1 #include <map&g

POJ 3686.The Windy&#39;s 最小费用最大流

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5477   Accepted: 2285 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The ma

POJ 2195:Going Home(最小费用最大流)

http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大流.最小费用最大流是保证在流量最大的情况下,使得费用最小. 建图是把S->人->家->T这些边弄上形成一个网络,边的容量是1(因为一个人只能和一个家匹配),边的费用是曼哈顿距离,反向边的费用是-cost. 算法的思想大概是通过SPFA找增广路径,并且找的时候费用是可以松弛的.当找到这样一条增

POJ 2516 Minimum Cost(最小费用最大流啊)

题目链接:http://poj.org/problem?id=2516 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (mar