HDU 6437 最小费用最大流

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Game_Acm/article/details/81951250

题目链接

题意:

一天有n个小时,有m部视频,有k个人,每个视频有一个放映起始时间,放映终止时间,可获得愉悦值,电影类型,当同一个人连续看两场同类型视频时对于当前看的视频获得的愉悦值减少w,求k个人获得的总愉悦值最大为多少(视频类型仅有两种)

思路:

按时间顺序为两类视频类型建立两条时间线(假设第一条为1->n,第二条为n+1->n+n)建立一个超级源点和一个源点,超级源点向源点建立一条流量为k费用为0的边表示最多可以有k个人,源点向两个时间线的起点1和1+n建立一条流量无限费用为0的边表示某一人开始走时间线,时间线的终点n和n+n向汇点建立一条流量无限费用为0的边表示某一人走完了时间线,当有视频时比如开始放映时间为S结束放映时间为T,先从视频向该视频源点建立一条边(第i个视频用n+n+i表示其视频源点)表示该视频只能被看一次,然后由视频向同时间线上的T连接费用为v-w的边向另一条时间线上的T连接费用为v的边,分别表示前一次看的视频为同类型和不同类型情况下看该视频的愉悦值收益

C++代码:

#include<bits/stdc++.h>
using namespace std;
int Abs( int a ){ return a>0?a:-a; }
int Max( int a , int b ){ return a>b?a:b; }
int Min( int a , int b ){ return a<b?a:b; }
int Gcd( int a , int b ){ return b==0?a:Gcd( b , a%b ); }
const int maxn = 610;
const int maxm = 2*610*610;
const int inf  = 0x3f3f3f3f;

int n,m,k,w;
struct edge
{
    int to,cap,cost,next;
}es[maxm];
int tol,max_flow,min_cost;
int head[maxn],dis[maxn],vis[maxn];

void init()
{
    tol = max_flow = min_cost = 0;
    memset ( head , -1 , sizeof(head) );
}

void addedge( int u , int v , int c , int w )
{
    es[tol].to = v;
    es[tol].cap = c;
    es[tol].cost = w;
    es[tol].next = head[u];
    head[u] = tol++;
    es[tol].to = u;
    es[tol].cap = 0;
    es[tol].cost = -w;
    es[tol].next = head[v];
    head[v] = tol++;
}

int spfa( int s , int t )
{
    memset ( vis , 0 , sizeof(vis) );
    for ( int i=s ; i<=t ; i++ ) dis[i] = inf;
    queue<int>Q; Q.push(t); dis[t] = 0; vis[t] = 1;
    while ( !Q.empty() )
    {
        int u = Q.front(); Q.pop(); vis[u] = 0;
        for ( int i=head[u] ; i!=-1 ; i=es[i].next )
        {
            int v = es[i].to,w = es[i].cost;
            if ( es[i^1].cap&&dis[v]>dis[u]-w )
            {
                dis[v] = dis[u]-w;
                if ( !vis[v] )
                {
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
    return dis[s]<inf;
}

int dfs( int t , int u , int flow )
{
    vis[u] = 1;
    if ( u==t ) return flow;
    int used = 0;
    for ( int i=head[u] ; i!=-1 ; i=es[i].next )
    {
        int v = es[i].to,w = es[i].cost;
        if ( !vis[v]&&es[i].cap&&dis[v]==dis[u]-w )
        {
            int new_flow = dfs( t , v  , Min( flow-used , es[i].cap ) );
            if ( new_flow )
            {
                used += new_flow;
                es[i].cap  -= new_flow;
                es[i^1].cap+= new_flow;
                min_cost += new_flow*w;
            }
        }
        if ( used==flow ) break;
    }
    return used;
}

void MCMF( int s , int t )
{
    while ( spfa( s , t ) )
    {
        do
        {
            memset ( vis , 0 , sizeof(vis) );
            max_flow += dfs( t , s , inf );
        }
        while ( vis[t] );
    }
    printf ( "%d\n" , -min_cost );
}

int main()
{
    for ( int T ; scanf ( "%d" , &T )==1 ; )
    {
        for ( int cas=1 ; cas<=T ; cas++ )
        {
            init();
            scanf ( "%d%d%d%d" , &n , &m , &k , &w );
            addedge( 0 , n+n+m+1 , k , 0 );
            addedge( n+n+m+1 , 1 , inf , 0 );
            addedge( n+n+m+1 , n+1 , inf , 0 );
            addedge( n , n+n+m+2 , inf , 0 );
            addedge( n+n , n+n+m+2 , inf , 0 );
            for( int i=1 ; i<n ; i++ )
            {
                addedge( i , i+1 , inf , 0 );
                addedge( n+i , n+i+1 , inf , 0 );
            }
            for ( int i=1 ; i<=m ; i++ )
            {
                int s,t,v,p; scanf ( "%d%d%d%d" , &s , &t , &v , &p );
                s = s+n*p;
                t = t+n*p;
                addedge( s , n+n+i , 1 , 0 );
                addedge( n+n+i , t , 1 , -v+w );
                if ( t>n ) t -= n; else t += n;
                addedge( n+n+i , t , 1 , -v );
            }
            MCMF( 0 , n+n+m+2 );
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Game_Acm/article/details/81951250