多校第一场:HDU 4862 最小费用最大流

思路:这题主要是建图搞了好久,以前没判断过满流,所以又看了这个知识点,然后才发现自己的最小费用最大流在求满流的时候有bug,正好改了过来。

建图:开始看题解知道这题是最小费用最大流,然后没看解释就做了。然后自己建的图没得求出答案,然后想了好久也没发现哪里错。然后看了官方题解,发现自己的建图和官方差太大了。可能是受昨天做POJ最小费用建图的影响吧。官方的建太符合题目意思了,只能说,我还看了好久建图才理解的。

构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0;Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0;如果X部的节点x可以在一步之内到达Y部的节点y(即题目中说的可以向右或者向下走),那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量(这题求最大费用最大流,所以是负数),流量1;再在X部增加一个新的节点,表示可以从任意节点出发K次(这个我还理解了很久才知道的,原因是比如第三个样例,1和2的点每点只能一步就退出了,所以新建的这个点是为了第三个样例这种情况存在的),源点向其连边,费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流;如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量。

代码解释:b[i][j]*2-1表示每个点拆点后这个点属于左部图,b[i][j]*2表示右部图。

#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 sink,cnt,flow,minflow;
int head[maxn],que[maxn*10],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 <= sink; i ++)
        dis[i] = INF,vis[i] = false;
    dis[0]=0,que[0]=0,minflow=INF,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;
                minflow=min(minflow,e[i].w);
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    que[r++] = v;
                }
            }
        }
        vis[u] = false;
    }
    return dis[sink]!=INF;
}
int change()
{
    int i,p;
    for(i=sink; i!=0; i=e[e[p].re].v)
    {
        p=pre[i];
        e[p].w-=minflow;
        e[e[p].re].w+=minflow;
    }
    flow+=minflow;
    return minflow*dis[sink];
}
int EK()
{
    int sum=0;
    while(spfa()) sum+=change();
    return sum;
}
void init()
{
    mem(head,-1),mem(pre,0),cnt=0,flow=0;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int t,ii=1;
    scanf("%d",&t);
    while(t--)
    {
        init();
        int N,M,K,i,j,k,z,tmp=0,b[10][11];
        char s[10][11];
        scanf("%d%d%d",&N,&M,&K);
        for(i=0; i<N; i++) scanf("%s",s[i]);
        for(i=0; i<N; i++)
            for(j=0; j<M; j++)
                b[i][j]=++tmp;
        for(i=0; i<N; i++)
            for(j=0; j<M; j++)
            {
                for(k=j+1; k<M; k++)//向右走
                {
                    z=0;
                    if(s[i][j]==s[i][k]) z=s[i][j]-'0';
                    add(b[i][j]*2-1,b[i][k]*2,1,k-j-1-z);
                }
                for(k=i+1;k<N;k++)//向下走
                {
                    z=0;
                    if(s[i][j]==s[k][j]) z=s[i][j]-'0';
                    add(b[i][j]*2-1,b[k][j]*2,1,k-i-1-z);
                }
            }
        int New=tmp*2+1;
        add(0,New,K,0);//源点与左部新建结点连
        for(i=0;i<N;i++)
            for(j=0;j<M;j++)
            {
                add(0,b[i][j]*2-1,1,0);//源点与左部每个点都相连
                add(New,b[i][j]*2,1,0);//新建结点与右部每个结点连
            }
        sink=tmp*2+2;
        for(i=0;i<N;i++)
            for(j=0;j<M;j++)//汇点与右部每个点也连
                add(b[i][j]*2,sink,1,0);
        int ans=EK();
        printf("Case %d : ",ii++);
        if(flow!=N*M) puts("-1");
        else printf("%d\n",-ans);
    }
    return 0;
}
时间: 2024-10-09 04:54:42

多校第一场:HDU 4862 最小费用最大流的相关文章

hdu 2516 最小费用最大流

原来这个代码超时 #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define N 200 #define inf 0x3fffffff int cap[N][N]; int fee[N][N]; int s,t,sum,pre[N]; int spfa() { queue<int>q; int dis[N],visit[N],u,i; memset(pre

hdu 1533(最小费用最大流)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4223    Accepted Submission(s): 2178 Problem Description On a grid map there are n little men and n houses. In each unit time, every l

HDU 1533 最小费用最大流(模板)

http://acm.hdu.edu.cn/showproblem.php?pid=1533 这道题直接用了模板 题意:要构建一个二分图,家对应人,连线的权值就是最短距离,求最小费用 要注意void init(int n) 这个函数一定要写 一开始忘记写这个WA了好几发 还有这个题很容易T掉,赋值建图要简化,一开始构建成网络流那种图一直T #include <stdio.h> #include <string.h> #include <iostream> #includ

hdu 6437 /// 最小费用最大流 负花费 SPFA模板

题目大意: 给定n,m,K,W 表示n个小时 m场电影(分为类型A.B) K个人 若某个人连续看了两场相同类型的电影则失去W 电影时间不能重叠 接下来给定m场电影的 s t w op 表示电影的 开始时间s 结束时间t 看完这场电影则获得w 电影类型是op(0为A 1为B) 将一场电影拆成两个点 s t,两点间连线花费为-w容量为1 源点与所有电影的s点连线 花费为0容量为1 所有电影的t点与汇点连线 花费为0容量为1 若两场电影的时间不冲突 那么按时间顺序在之间连边 若类型相同 花费为W容量为

hdu 3667(最小费用最大流+拆边)

Transportation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2670    Accepted Submission(s): 1157 Problem Description There are N cities, and M directed roads connecting them. Now you want to

hdu 5294 Tricks Device(2015多校第一场第7题)最大流+最短路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5294 题意:给你n个墓室,m条路径,一个人在1号墓室(起点),另一个人在n号墓室(终点),起点的那个人只有通过最短路径才能追上终点的那个人,而终点的那个人能切断任意路径. 第一问--终点那人要使起点那人不能追上的情况下可以切的最少的路径数,输出最少的路径数 第二问--起点那人能追上终点那人的情况下,终点那人能切断的最多的路径数,输出最多的路径数 思路:要使起点那人无法追上,只要使他的最短路径不存在就

[2019HDU多校第一场][HDU 6590][M. Code]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6590 题目大意(来自队友):二维平面上有\(n\)个点,每个点要么是黑色要么是白色,问能否找到一条直线将平面分割成黑白两部分 题解:分别对每种颜色的点求凸包,判断是否相交即可. (有模板真好) 1 #include<bits/stdc++.h> 2 //#include<cstdio> 3 //#include<cmath> 4 //#include<algorith

【网络流#2】hdu 1533 最小费用最大流模板题

嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边 按照这个图跑一发费用流即可 把代码挂上去,用的是前向星写的 1 #include<cstdio> 2 #include<cstr

HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4862 题意: 给你一个n*m的矩阵,填充着0-9的数字,每次能从一个点出发,到它的右边或者下边的点,花费为|x1-x2|+|y1-y2|-1,如果跳跃的起点和终点的数字相同,则获得这个数字的收益,不能走已经走过的点 有K次重新选择起点的机会 如果可以走遍所有点,则输出最大的价值(收益-花费) 否则,输出-1 方法: 最小K路径覆盖,最小费用最大流 建图: 每个点拆为2点:X部和Y部,(a,b)表示流量