hdu 2853 Assignment 费用流

就是本来就给出了一个匹配,然后让你求一个权值最大的匹配,并且和初始匹配变动最小。

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
const int N=400;
const int MAXE=20000000;
const int inf=1<<30;
int head[N],s,t,cnt,ans;
int d[N],pre[N];
bool vis[N];
int q[MAXE];
int map[200][200],fee[200][200];
struct Edge
{
    int u,v,c,w,next;
}edge[MAXE];

void addedge(int u,int v,int w,int c)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].c=c;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].u=v;
    edge[cnt].w=-w;
    edge[cnt].c=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

int SPFA()
{
    int l,r;
    memset(pre,-1,sizeof(pre));
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=t;i++) d[i]=inf;
    d[s]=0;
    l=0;r=0;
    q[r++]=s;
    vis[s]=1;
    while(l<r)
    {
        int u=q[l++];
        vis[u]=0;
        for(int j=head[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].c>0&&d[u]+edge[j].w<d[v])
            {
                d[v]=d[u]+edge[j].w;
                pre[v]=j;
                if(!vis[v])
                {
                    vis[v]=1;
                    q[r++]=v;
                }
            }
        }
    }
    if(d[t]==inf)
        return 0;
    return 1;
}

void MCMF()
{
    int flow=0;
    while(SPFA())
    {
        int u=t;
        int mini=inf;
        while(u!=s)
        {
            if(edge[pre[u]].c<mini)
                mini=edge[pre[u]].c;
                u=edge[pre[u]].u;
        }
        flow+=mini;
        u=t;
        ans+=d[t]*mini;
        while(u!=s)
        {
            edge[pre[u]].c-=mini;
            edge[pre[u]^1].c+=mini;
            u=edge[pre[u]].u;
        }
    }
}

int main()
{
    int nn,mm;
    while(scanf("%d%d",&nn,&mm)!=EOF)
    {
        int i,j,u;
        cnt=0;
        s=0;t=nn+mm+1;
        for(i=0;i<=t;i++)
            head[i]=-1;
        memset(map,0,sizeof(map));
        for(i=1;i<=nn;i++)
            for(j=1;j<=mm;j++)
                scanf("%d",&fee[i][j]);
        int init=0;
        for(i=1;i<=nn;i++)
        {
            scanf("%d",&u);
            map[i][u]=1;
            init+=fee[i][u];
            addedge(s,i,0,1);
        }
        for(i=1;i<=mm;i++) addedge(i+nn,t,0,1);
        for(i=1;i<=nn;i++)
            for(j=1;j<=mm;j++)
            {
                if(map[i][j])
                    addedge(i,j+nn,-fee[i][j]*51-1,1);
                else addedge(i,j+nn,-fee[i][j]*51,1);
            }
        ans=0;
        MCMF();
        printf("%d %d\n",nn+ans%51,(-ans/51)-init);
    }
    return 0;
}

hdu 2853 Assignment 费用流

时间: 2024-10-06 17:26:06

hdu 2853 Assignment 费用流的相关文章

HDU 4862 Jump 费用流

又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选任意之前没有走过的格子作为起点.然后走任意步,其中每一步你可以向右或者向下走任意格.假如从(x1, y1)走到(x2, y2)需要花费能量|x1-x2|+|y1-y2|-1,如果这一步和上一步格子的数字相同,那么可以获得格子上相应数字的能量.能量可以为负值. 问你,在K次以内走完所以格子最多能得到多

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

HDU 2853 Assignment(KM最大匹配好题)

HDU 2853 Assignment 题目链接 题意:现在有N个部队和M个任务(M>=N),每个部队完成每个任务有一点的效率,效率越高越好.但是部队已经安排了一定的计划,这时需要我们尽量用最小的变动,使得所有部队效率之和最大.求最小变动的数目和变动后和变动前效率之差. 思路:对于如何保证改变最小,没思路,看了别人题解,恍然大悟,表示想法非常机智 试想,如果能让原来那些匹配边,比其他匹配出来总和相同的权值还大,对结果又不影响,那就简单了,这个看似不能做到,其实是可以做到的 数字最多选出50个,所

HDU 4411 Arrest 费用流

题目链接:点击打开链接 题意: 给定n+1个点([0,n] )m条边的无向图.起点为0,k个人初始在起点, 去遍历图使得每个点至少被一人走过且遍历 i 点时 i-1 必须已经被遍历. 使得k人的路径和最小,最后k人要回到起点. 思路: 费用流,因为对于一个人来说,这个人遍历点的序列一定是一个递增序列(不需要连续) 所以建图时i的出点只需要连接i+? 的入点. 若建一个完全图则会因为spfa跑负环... #include<iostream> #include<stdio.h> #in

hdu 2853 Assignment KM算法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853 Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of t

Going Home HDU - 1533 (费用流)

Going Home HDU - 1533 1 //费用流初探 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #include <cstdio> 6 #include <algorithm> 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 110; 10 char gra

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

hdu 4862 Jump 上下界费用流

对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次. 然后若点u可到达点v,则连接即可.建成了一个上下界网络,将下界拆出去,求最大费用最大流就好. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<3

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege