码迷,mamicode.com
首页 > 其他好文 > 详细

Remember the A La Mode

时间:2020-02-17 17:59:13      阅读:49      评论:0      收藏:0      [点我收藏+]

标签:超级   while   +=   div   cin   str   个数   最小值   out   

这道题是一个裸网络流

不过要注意以下几点:

1、题目中的输入是浮点数(有个毒瘤,我自己写的网络流结果tle,看了大佬代码把浮点数整形化就过了)

2、这个题目是练习超级源点和超级汇点的不错的题

3、求最大的网络流就把cost取反求最小值就行

以下是代码

//抽象为一个图源点和汇点是无穷的边
//超级源点和超级汇点的连边容量来约束饼干的个数和冰淇淋的个数
//每个边的权重是这两个种类合并的收益
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N =10010;
const int INF = 0x3f3f3f3f;

// const int MAX=110;

int vi[N],pre[N],numsp[N],numsl[N];
int pos[N][N];
int dis[N];
int maxcost=0,mincost=0;
int p,l;


struct edg{
    int from,to;
    int cap;
    int flow;
    int cost;
}edgs[N];




int h[N],ne[N],idx=0;
void add(int a,int b,int cap,int w){
    edgs[idx]={a,b,cap,0,w};
    ne[idx]=h[a];
    h[a]=idx++;
}


bool spfa(int s,int t){
    memset(pre,-1,sizeof pre);
    memset(vi,0,sizeof vi);
    memset(dis,0x3f,sizeof dis);
    queue<int> q;
    q.push(s);
    vi[s]=1;
    dis[s]=0;
    pre[s]=-1;
    while(!q.empty()){
        int tem=q.front();
        q.pop();
        vi[tem]=0;
        for(int i=h[tem];~i;i=ne[i]){
            int to=edgs[i].to;
            if(edgs[i].cap>0&&dis[to]>dis[tem]+edgs[i].cost){
                dis[to]=dis[tem]+edgs[i].cost;
                pre[to]=i;
                if(!vi[to]){
                    q.push(to);
                    vi[to]=1;
                }
            }
            
        }
    }
    return pre[t]!=-1;
}

void mcmf(int s,int t){
    while(spfa(s,t)){
        int now=t;
        int nowflow=INF;
        // for(int i=pre[t];i!=-1;i=pre[edgs[i].from]){
        //     nowflow=min(nowflow,edgs[i].cap);
        // }
        while(now!=s){
            nowflow=min(nowflow,edgs[pre[now]].cap);
            now=edgs[pre[now]].from;
        }
        // // cout<<nowflow<<endl;
        // cout<<mincost<<endl;
        // for(int i=pre[t];i!=-1;i=pre[edgs[i].from]){
        //     edgs[i].cap-=nowflow;
        //     edgs[i^1].cap+=nowflow;
        // }
        now=t;
        mincost+=nowflow*dis[t];
        while(now!=s){
            // edgs[pre[now]].flow=nowflow;
            edgs[pre[now]].cap-=nowflow;
            edgs[pre[now]^1].cap+=nowflow;
            now=edgs[pre[now]].from;
        }
    }
}

int main(){
    cin>>p>>l;
    for(int i=1;i<=p;i++)cin>>numsp[i];
    for(int i=1;i<=l;i++)cin>>numsl[i];
    memset(h,-1,sizeof h);
    for(int i=1;i<=p;i++){
        for(int j=p+1;j<=p+l;j++){
            double cost;
            cin>>cost;
            if(cost>0){
                cost=cost*100+0.5;
                cost=(int)cost;
                pos[i][j]=cost;
                add(i,j,INF,-cost);
                add(j,i,0,cost);
            }
            else{
                pos[i][j]=0;
            }
        }
    }
    for(int i=1; i <= p;i++){
        add(0,i,numsp[i],0);
        add(i,0,0,0);   
    }
    for(int i=p+1;i <= p+l;i++){
        add(i,p+l+1,numsl[i-p],0);
        add(p+l+1,i,0,0);
    }
    // for(int i=h[1];~i;i=ne[i]){
    //     cout<<edgs[i].to<<" "<<edgs[i].cost<<endl;
    // }
    mcmf(0,p+l+1);
    maxcost=(-mincost);
    mincost=0;
    idx=0;
    memset(h,-1,sizeof h);
    for(int i=1;i<=p;i++){
        for(int j=p+1;j<=p+l;j++){
            if(pos[i][j]>0){
                add(i,j,INF,pos[i][j]);
                add(j,i,0,-pos[i][j]);
            }
        }
    }
    for(int i=1; i <= p;i++){
        add(0,i,numsp[i],0);
        add(i,0,0,0);   
    }
    for(int i=p+1;i <= p+l;i++){
        add(i,p+l+1,numsl[i-p],0);
        add(p+l+1,i,0,0);
    }
    mcmf(0,p+l+1);
    printf("%.2lf to %.2lf",mincost/100.0,maxcost/100.0);
    // cout<<mincost/100.0<<" to "<<maxcost/100.0<<endl;
    
    
}

 

Remember the A La Mode

标签:超级   while   +=   div   cin   str   个数   最小值   out   

原文地址:https://www.cnblogs.com/kstranger/p/12322625.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!