无法拯救我的菜----焦作网络赛 F. Modular Production Line

地址:https://nanti.jisuanke.com/t/31715

poj3680原题,数据都一样,是最小费用最大流摸板题
转载:https://blog.csdn.net/zhou_yujia/article/details/52411251
先看一下poj3680:
离散化所有区间的端点,把每个端点看做一个顶点,建立附加源S汇T。
1、从S到顶点1(最左边顶点)连接一条容量为K,费用为0的有向边。
2、从顶点2N(最右边顶点)到T连接一条容量为K,费用为0的有向边。
3、从顶点i到顶点i+1(i+1<=2N),连接一条容量为无穷大,费用为0的有向边。
4、对于每个区间[a,b],从a对应的顶点i到b对应的顶点j连接一条容量为1,费用为区间长度的有向边。
求最大费用最大流,最大费用流值就是最长k可重区间集的长度。
这个问题可以看做是求K条权之和最大的不想交路径,每条路径为一些不相交的区间序列。由于是最大费用流,两条路径之间一定有一些区间相交,可以看做事相交部分重复了2次,
而K条路经就是最多重复了K次。最简单的想法就是把区间排序后,不相交的区间之间连接一条边,由于每个区间只能用一次,所以要拆点,点内限制流量
在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 405;
const int MAXM = 100005;

typedef struct Node{
    int s,to,next,capacity,value;
}Node;

int n,k;
int ecnt;
Node node[MAXM];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
bool vis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
vector<int>ve;
map<int,int>mp;

void init()
{
    ecnt = 0;
    memset(head,-1,sizeof(head));
    memset(node,0,sizeof(node));
}

void addEdge(int u,int v,int w,int c)
{
    node[ecnt].to = v;
    node[ecnt].s = u;
    node[ecnt].capacity = c;//流量
    node[ecnt].value = w;//路径长度是费用
    node[ecnt].next = head[u];
    head[u] = ecnt++;
    node[ecnt].to = u;
    node[ecnt].s = v;
    node[ecnt].capacity = 0;//流量
    node[ecnt].value = -w;//路径长度是费用
    node[ecnt].next = head[v];
    head[v] = ecnt++;
}

bool spfa(int s,int t,int nnum)
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i = 0;i <= nnum;++i)
    {
        dis[i] = inf;
    }
    queue<int>que;
    que.push(s);
    dis[s] = 0;
    vis[s] = true;
    while(!que.empty())
    {
        int temp = que.front();
        que.pop();
        vis[temp] = false;
        for(int i = head[temp];i + 1;i = node[i].next)
        {
            if(node[i].capacity)
            {
                int ne = node[i].to;
                if(dis[temp] + node[i].value < dis[ne]){
                    dis[ne] = dis[temp] + node[i].value;
                    pre[ne] = i;
                    if(!vis[ne]){
                        que.push(ne);
                        vis[ne] = true;
                    }
                }
            }
        }
//        for(int i = 0;i <= nnum;++i)
//            cout << dis[i] << " ";
//        cout << endl;
    }
    if(dis[t] == inf)
        return false;
    return true;
}

int getMincost(int s,int t,int nnum)
{
    int ans_flow = 0;
    int ans_cost = 0;
    int temp,minc;
    while(spfa(s,t,nnum))
    {
//        cout << 0 << endl;
        temp = t;
        minc = inf;
        while(pre[temp] != -1)
        {
            minc = min(node[pre[temp]].capacity,minc);
            temp = node[pre[temp]].s;
        }
        temp = t;
        while(pre[temp] != -1)
        {
            node[pre[temp]].capacity -= minc;
            int ss = pre[temp] ^ 1;
            node[ss].capacity += minc;
            temp = node[pre[temp]].s;
        }
        //cout << dis[t] << " " << minc << endl;
//        for(int i = s;i <= t;++i)
//        {
//            cout << dis[i] << " ";
//        }
//        cout << endl;
        ans_cost += dis[t] * minc;
    }
    return ans_cost;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mp.clear();ve.clear();
        init();
        scanf("%d %d",&n,&k);
        for(int i = 1;i <= n;++i)
        {
            scanf("%d %d %d",&u[i],&v[i],&w[i]);
            ve.push_back(u[i]);
            ve.push_back(v[i]);
        }
        sort(ve.begin(),ve.end());
        ve.erase(unique(ve.begin(),ve.end()),ve.end());
        int s = 0;
        int t = ve.size() + 1;
        int len = ve.size();
        for(int i = 0;i < len;++i)
            mp[ve[i]] = i + 1;
        addEdge(s,1,0,k);
        addEdge(ve.size(),t,0,k);
        for(int i = 1;i < len;++i)
            addEdge(i,i + 1,0,inf);
        for(int i = 1;i <= n;++i)
            addEdge(mp[u[i]],mp[v[i]],-w[i],1);
        int res = getMincost(s,t,t);
        printf("%d\n",-1 * res);
    }
    return 0;
}

再看F这道题,区间变了而已,改为把A[i] - 1 放入数组即可
注意:为什么建边把权值变为负呢,模板是最小费用最大流,每次用spfa找增广路径时,找到的是最小权值和,题意应该是找最大权值和

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 405;
const int MAXM = 100005;

typedef struct Node{
    int s,to,next,capacity,value;
}Node;

int n,k,m;
int ecnt;
Node node[MAXM];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
bool vis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
vector<int>ve;
map<int,int>mp;

void init()
{
    ecnt = 0;
    memset(head,-1,sizeof(head));
    memset(node,0,sizeof(node));
}

void addEdge(int u,int v,int w,int c)
{
    node[ecnt].to = v;
    node[ecnt].s = u;
    node[ecnt].capacity = c;//流量
    node[ecnt].value = w;//路径长度是费用
    node[ecnt].next = head[u];
    head[u] = ecnt++;
    node[ecnt].to = u;
    node[ecnt].s = v;
    node[ecnt].capacity = 0;//流量
    node[ecnt].value = -w;//路径长度是费用
    node[ecnt].next = head[v];
    head[v] = ecnt++;
}

bool spfa(int s,int t,int nnum)
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i = 0;i <= nnum;++i)
    {
        dis[i] = inf;
    }
    queue<int>que;
    que.push(s);
    dis[s] = 0;
    vis[s] = true;
    while(!que.empty())
    {
        int temp = que.front();
        que.pop();
        vis[temp] = false;
        for(int i = head[temp];i + 1;i = node[i].next)
        {
            if(node[i].capacity)
            {
                int ne = node[i].to;
                if(dis[temp] + node[i].value < dis[ne]){
                    dis[ne] = dis[temp] + node[i].value;
                    pre[ne] = i;
                    if(!vis[ne]){
                        que.push(ne);
                        vis[ne] = true;
                    }
                }
            }
        }
//        for(int i = 0;i <= nnum;++i)
//            cout << dis[i] << " ";
//        cout << endl;
    }
    if(dis[t] == inf)
        return false;
    return true;
}

int getMincost(int s,int t,int nnum)
{
    int ans_flow = 0;
    int ans_cost = 0;
    int temp,minc;
    while(spfa(s,t,nnum))
    {
//        cout << 0 << endl;
        temp = t;
        minc = inf;
        while(pre[temp] != -1)
        {
            minc = min(node[pre[temp]].capacity,minc);
            temp = node[pre[temp]].s;
        }
        temp = t;
        while(pre[temp] != -1)
        {
            node[pre[temp]].capacity -= minc;
            int ss = pre[temp] ^ 1;
            node[ss].capacity += minc;
            temp = node[pre[temp]].s;
        }
        //cout << dis[t] << " " << minc << endl;
//        for(int i = s;i <= t;++i)
//        {
//            cout << dis[i] << " ";
//        }
//        cout << endl;
        ans_cost += dis[t] * minc;
    }
    return ans_cost;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mp.clear();ve.clear();
        init();
        scanf("%d %d %d",&m,&k,&n);
        for(int i = 1;i <= n;++i)
        {
            scanf("%d %d %d",&u[i],&v[i],&w[i]);
            ve.push_back(u[i] - 1);
            ve.push_back(v[i]);
        }
        sort(ve.begin(),ve.end());
        ve.erase(unique(ve.begin(),ve.end()),ve.end());
        int s = 0;
        int t = ve.size() + 1;
        int len = ve.size();
        for(int i = 0;i < len;++i)
            mp[ve[i]] = i + 1;
        addEdge(s,1,0,k);
        addEdge(ve.size(),t,0,k);
        for(int i = 1;i < len;++i)
            addEdge(i,i + 1,0,inf);
        for(int i = 1;i <= n;++i)
            addEdge(mp[u[i] - 1],mp[v[i]],-w[i],1);
        int res = getMincost(s,t,t);
        printf("%d\n",-1 * res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/82793806
今日推荐