HDU 5045 费用流求最大权

点击打开链接

题意:有n个人和m到题目,每个人做对的概率以矩阵形式给出,问如何分配才可以使做对的概率最大,有一个限制条件是做到目前为止每两个人的做题数量差距不能超过1,也就是前n道题目,必须一人做一个

思路:网上都是dp多一点,用网络流也可以,不过麻烦很多,可是本弱是一点dp都不会的选手啊,只能用网络流了,对于那个限制条件,我们可以以前n道题建一次图,然后再来n个,不过就直接建完就可以了,然后我们要求的是什么呢,很明显是最大权,而最大费用最大流刚好可以解决,这里面的费用流有两种方法,用spfa找最短路或者用dijkstra找最短路,用spfa会方便很多,因为它可以处理带负的权值边,dijkstra不可以,这道题就是要讲权值变负,求最小费用最大流,然后将结果取负就可以了,本弱喜欢用dijkstra,处理的很麻烦,有兴趣的可以看看,建议用spfa

#include <queue>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
const double inf=1000.0;
const int maxn=1050;
typedef pair<double,int> P;
struct edge{
    int to,cap,rev;
    double cost;
    edge();
    edge(int a,int b,double c,int d){to=a,cap=b,cost=c,rev=d;};
};
vector<edge>G[maxn];
double h[maxn],dis[maxn];
int prevv[maxn],preve[maxn];
void addedge(int st,int en,int cap,double cost){
    G[st].push_back(edge(en,cap,cost,G[en].size()));
    G[en].push_back(edge(st,0,-cost,G[st].size()-1));
}
double min_cost_flow(int st,int en,int f){
    double ans=0;
    memset(h,0,sizeof(h));
    while(f>0){
        priority_queue<P,vector<P>,greater<P> >que;
        for(int i=0;i<maxn;i++) dis[i]=inf;
        dis[st]=0;que.push(P(0,st));
        while(!que.empty()){
            P p=que.top();que.pop();
            int v=p.second;
            if(dis[v]<p.first) continue;
            for(unsigned int i=0;i<G[v].size();i++){
                edge &e=G[v][i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                    dis[e.to]=dis[v]+e.cost+h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    que.push(P(dis[e.to],e.to));
                }
            }
        }
        if(dis[en]==inf) return -1;
        for(int i=0;i<maxn;i++) h[i]+=dis[i];
        int d=f;
        for(int i=en;i!=st;i=prevv[i]){
            d=min(d,G[prevv[i]][preve[i]].cap);
        }
        f-=d;
        ans+=d*h[en];
        for(int i=en;i!=st;i=prevv[i]){
            edge &e=G[prevv[i]][preve[i]];
            e.cap-=d;
            G[i][e.rev].cap+=d;
        }
    }
    return ans;
}
double A[15][1010];
int main(){
    int T,n,m,T1=1;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++) scanf("%lf",&A[i][j]);
        }
        double ans=0,max1=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(A[i][j]>max1) max1=A[i][j];
                A[i][j]*=-1;
            }
        }
        max1+=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) A[i][j]+=max1;
        int t=1;
        while(t<=m){
            for(int i=0;i<maxn;i++) G[i].clear();
            int kk=1,tt=t,ttt=t;
            for(;tt<=m&&kk<=n;tt++,kk++) addedge(tt+n,n+m+1,1,0);
            for(int i=1;i<=n;i++) addedge(0,i,1,0);
            for(int i=1;i<=n;i++){
                int k=1;
                for(int j=t;j<=m&&k<=n;j++,k++){
                    addedge(i,n+j,1,A[i][j]);
                }
            }
            t+=n;
            int ff;
            if(t<=m) ff=n;
            else ff=m-ttt+1;
            ans+=min_cost_flow(0,n+m+1,ff);
        }
        max1=max1*m;
        double ans1=(ans-max1)*(-1);
        printf("Case #%d: %.5lf\n",T1++,ans1);
    }
    return 0;
}
时间: 2024-07-30 00:23:43

HDU 5045 费用流求最大权的相关文章

hdu 5045 费用流

滚动建图,最大费用流(每次只有就10个点的二分图).复杂度,m/n*(n^2)(n<=10),今年网络赛唯一网络流题,被队友状压DP秒了....难道网络流要逐渐退出历史舞台???.... #include<iostream> //78ms #include<cstdio> #include<queue> using namespace std; const double inf =0x3f3f3f3f; const int maxv=50,maxe=500; in

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 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

HDU 3376 费用流 Matrix Again

咳咳,内个,内什么,白书上的费用流模板没过,后来换了种存图方式才过. 题意: 给出一个n × n的矩阵,每个格子中有一个数字代表权值,找出从左上角出发到右下角的两条不相交的路径(起点和终点除外),使得两条路径权值之和最大. 分析: 如果n比较小的话是可以DP的,但是现在n非常大,DP会超时的. 这个用费用流来求解: 因为每个点只能走一次,所以先拆点,两点之间连一条容量为1费用为对应格子权值的边,如果是起点或终点,因为要走两次,所以要连容量为2的边. 对于不同格子之间,如果能到达,连一条容量为IN

POJ2195 Going Home[费用流|二分图最大权匹配]

Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertica

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

【BZOJ 3308】 3308: 九月的咖啡店 (费用流|二分图最大权匹配)

3308: 九月的咖啡店 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 244  Solved: 86 Description 深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这里若干种兑在一起.不过有些原料不能同时在一杯中,如果两个编号为i,j的原料,当且仅当i与j互质时,才能兑在同一杯中.现在想知道,如果用这N种原料来调同一杯咖啡,使用的原料编号之和最大可为多少. In

hdu 4406 费用流

这题问题就是当前时刻到底选择哪门课程,易知选择是和分数有关的,并且是一个变化的权值,所以可以用拆点的方式,把从基础分到100分都拆成点,但若这样拆点的话,跑费用流时就必须保证顺序,这样就麻烦了..观察公式,发现同一门课,分数越高,权值是越低的,所以这是一个单调的,这样的话就可以对每一个分数建一条边,费用流会一条一条的跑. 注意将课程放在X集 #include<cstdio> #include<queue> #include<algorithm> #include<

HDU 3667 费用流 拆边 Transportation

题意: 有N个城市,M条有向道路,要从1号城市运送K个货物到N号城市. 每条有向道路<u, v>运送费用和运送量的平方成正比,系数为ai 而且每条路最多运送Ci个货物,求最小费用. 分析: 拆边,每条边拆成费用为a, 3a, 5a的边,这样就能保证每条边的费用和流量的平方成正比. 因为最多运送K个货物,所以增加一个源点和城市1连一条容量为K费用为0的边. 跑一边最小费用最大流,如果满流才有解. 1 #include <iostream> 2 #include <cstdio&