poj 3680 Intervals 经典的建图!

建图想了好久,想到了一种不需要s和t的建图方法,先离散化,具体建法是 i + 1 连 i ,正容量是 k ,逆容量是0 ,费用是0,然后根据区间的限制,连接 ai 和 bi (都是离散化后的数据),正向容量是 1,逆向是0,正费用是 -w,逆费用是 w(把正向费用和逆向费用互换求最大费就变成求最小费了),这样就不需要s 点和 t 点,求最大费,这种图求最大费的方法就是消负环了;可是消负环的代码很难写,而且复杂度很高,一般都是超时的,所以我还是放弃了这种消负环的建图方法;然后看了下discuss,牛逼!!!真tm牛逼!!原来这种建法可以改进!!!建图方法 ai 连 bi 不变,i+1 连 i 变成了 i 连 i+1 ,容量是 inf ,我当时疑惑为什么是 inf 啊??!!如果每条边都是 inf 那么最后每条边都要小于 k 的条件如何限制?!!答案令我惊讶,居然添加一个 s 连接到 1,添加一个 t 连接到最后一个!!同时,把消负圈转换为最小费最大流,完美!哥服了!!总结,有些时候只要再多想想就会有更好的方法!

#include<iostream>
#include<vector>
#include<cstring>
#include<string>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 431;
const int end = 430;

struct zz
{
    int from;
    int to;
    int c;
    int cost;
    int id;
}zx,tz;
int n,k,T,tot;
int a[maxn];
int b[maxn];
int w[maxn];
int fx[maxn];
map<int,int>m;
vector<int>v;
vector<int>vs;
vector<zz>g[maxn];
queue<int>q;
int way[maxn];
bool inq[maxn];
int backid[maxn];


inline void link(int now,int to,int c,int cost,int bc,int bcost)
{
    zx.from = now;
    zx.to = to;
    zx.cost = cost;
    zx.c = c;
    zx.id = g[to].size();
    g[now].push_back(zx);
    swap(zx.from,zx.to);
    zx.c = bc;
    zx.cost = bcost;
    zx.id = g[now].size() - 1;
    g[zx.from].push_back(zx);
    return ;
}

bool spfa()
{
    while(!q.empty())
    {
        q.pop();
    }
    for(int i=1;i<=tot;i++)
    {
        way[i] = inf;
    }
    way[end] = inf;
    way[0] = 0;
    memset(inq,false,sizeof(inq));
    memset(backid,-1,sizeof(backid));
    inq[0] = true;
    q.push(0);
    int now,to;
    int temp;
    int cost;
    int id;
    while(!q.empty())
    {
        now = q.front();
        q.pop();
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i].c > 0)
            {
                to = g[now][i].to;
                id = g[now][i].id;
                cost = g[now][i].cost;
                temp = way[now] + cost;
                if(temp < way[to])
                {
                    way[to] = temp;
                    backid[to] = id;
                    if(!inq[to])
                    {
                        q.push(to);
                        inq[to] = true;
                    }
                }
            }
        }
        inq[now] = false;
    }

    int nowid;
    temp = end;
    int minflow = inf;
    while(backid[temp] != -1)
    {
        id = backid[temp];
        now = g[temp][id].to;
        nowid = g[temp][id].id;
        minflow = min(minflow , g[now][nowid].c);
        temp = now;
    }
    temp = end;
    while(backid[temp] != -1)
    {
        id = backid[temp];
        now = g[temp][id].to;
        nowid = g[temp][id].id;
        g[now][nowid].c -= minflow;
        g[temp][id].c += minflow;
        temp = now;
    }
    if(way[end]!=inf)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int EK()
{
    int ans=0;
    while(true)
    {
        spfa();
        if(way[end]<0)
        {
            ans += way[end];
        }
        else
        {
            break;
        }
    }
    return -ans;
}


int main()
{
    cin>>T;
    while(T--)
    {
     //   cin>>n>>k;
        scanf("%d%d",&n,&k);
        v.clear();
        v.push_back(0);
        m.clear();
        vs.clear();
        for(int i=1;i<=n;i++)
        {
     //       cin>>a[i]>>b[i]>>w[i];
            scanf("%d%d%d",&a[i],&b[i],&w[i]);
            vs.push_back(a[i]);
            vs.push_back(b[i]);
        }
        sort(vs.begin(),vs.end());
        int temp = vs[0];
        v.push_back(temp);
        for(int i=1;i<vs.size();i++)
        {
            if(vs[i] != temp)
            {
                temp = vs[i];
                v.push_back(temp);
            }
            else
            {
                continue;
            }
        }
        for(int i = 1; i < v.size(); i++)
        {
            m[v[i]] = i;       // ÀëÉ¢»¯
        }
        tot = v.size() - 1;

        for(int i=0;i<maxn;i++)
        {
            g[i].clear();
        }
        link(0,1,k,0,0,0);
        link(tot,end,k,0,0,0);
        for(int i=1;i<tot;i++)
        {
            link(i,i+1,inf,0,0,0);
        }
        for(int i=1;i<=n;i++)
        {
            link(m[a[i]],m[b[i]],1,-w[i],0,w[i]);
        }
        printf("%d\n",EK());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值