码迷,mamicode.com
首页 > 移动开发 > 详细

HDU 5406 CRB and Apple 花样费用流向解法

时间:2015-08-21 21:20:38      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:

题意简化一下就是一个序列,找出两个最大不下降子序列使得他们的长度和最长。

 

= =作为一个DP渣,状态设计大概也就到了dp[i][j]表示第一个人最后一次取到i,第二个人取到j这个地方了。。怎么在可行复杂度内转移?不会啊望天。。

其实作为图论工作者第一反应是费用流,但是边数太多了没敢搞= =

 

然而其实费用流也是可以过的。(x, y)表示容量为x费用为y,

建图很简单,建源s和汇e,加一个点t限制从 源最多流量是2,也就是s->t(2, 0)。将各个点拆掉限制只能取一次,x->x‘(1, 1),容量1限制只能取一次,费用表示长度+1

t->x(1, 0) 可以从任意点开始。 x‘->e(1, 0) 可以从任意一个点结束。

跑最大费用最大流,然后就会T(喂)

 

记得POJ有一道题卡SPFA,但是改成栈就能过= = 

于是你顺手把它改成栈发现居然不T了(从一开始接触ACM,这个问题就一直困扰着我T T怎么才能构造出卡队列不卡栈的数据?T T求指导)

代码1,大概1400ms 左右。

技术分享
#include<cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;

const int N  = 2010;
const int M = 4000005;
const int INF = 0x3f3f3f3f;
struct point{
    int u,v, next, flow, cost;
    point(){};
    point(int x, int y , int z, int f, int c){
        u = x,  v=  y;  next = z,   flow = f, cost = c;
    };
}p[M];
int pre[N], head[N], d[N];
bool vis[N];
int s, e, no;
struct Info{
    int h, d;
    void scan(){
        scanf("%d%d", &h, &d);
    }
    bool operator<(const Info &I)const{
        if(h == I.h)    return d < I.d;
        return h > I.h;
    }
}info[N];
bool spfa(){
    stack<int>q;
    int x, y, now, i;
    memset(d, 0xc0, sizeof(d));
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    q.push(s);  d[s] = 0;   vis[s] = 1;
    while(!q.empty()){
        x = q.top();  q.pop();
        vis[x] = 0;
        for(i = head[x]; i != -1; i = p[i].next){
            y = p[i].v;
            if(p[i].flow && d[y] < d[x] + p[i].cost){
                d[y] = d[x] + p[i].cost;
                pre[y] = i;
                if(!vis[y]){
                    q.push(y);
                    vis[y] = 1;
                }
            }
        }
    }
    return (d[e] != d[e+1]);
}

int mcmf(){
    int maxflow = 0, i, minflow, mincost = 0;
    while(spfa()){
        minflow = INF + 1;
        for(i = pre[e]; i != -1; i = pre[p[i].u]) {
            if(p[i].flow < minflow)
                minflow = p[i].flow;
        }
        for(i = pre[e]; i != -1; i = pre[p[i].u]){
            p[i].flow -= minflow;
            p[i ^ 1].flow += minflow;
        }
        mincost += d[e] * minflow;
    }
    return mincost;
}

void init(){
    memset(head, -1, sizeof(head));
    no = 0;
}
void add(int x, int y, int f, int co){
    p[no] = point(x, y, head[x], f, co);    head[x] = no++;
    p[no] = point(y, x, head[y], 0, -co);   head[y] = no++;
}
int main(){
    int TC, n, i, j;
    scanf("%d", &TC);
    while(TC--){
        scanf("%d", &n);
        init();s = 0;  e = 2 * n + 2;
        for(i = 1; i <= n; i++){
            info[i].scan();
            add(i<<1, i << 1| 1, 1, 1);
            add(1, i << 1, 1, 0);
            add(i << 1 | 1, e, 1, 0);
        }
        sort(info + 1, info + n + 1);
        for(i = 1; i <= n; i++){
            for(j = i + 1; j <= n; j++){
                if(info[i].d <= info[j].d){
                    add(i<<1|1, j <<1, 1, 0);
                }
            }
        }
        add(s, 1, 2, 0);

        printf("%d\n", mcmf());
    }
    return 0;
}
View Code

 

接下来进入各种尝试优化阶段。

一开始企图改进建边的方式,具体见 http://blog.csdn.net/mxymxy1994mxy/article/details/47818397 这位大神的说法,空间省了很多,然而用普通队列搞还是T(当然也可能是我蠢(然而显然不是可能,事实上是就是我蠢,趴(为什么最近这么想吐槽自己))),单纯形是厉害ORZ,然而改成栈的SPFA,不到500ms就过了,是厉害啊。

 

代码2,其他都一样,修改了一下建边的方式

技术分享
        init();s = 0;  e = 2 * n + 2;
        for(i = 1; i <= n; i++){
            info[i].scan();
            add(i<<1, i << 1| 1, 1, -1);
            add(1, i << 1, 1, 0);
            add(i << 1 | 1, e, 1, 0);
        }
        sort(info + 1, info + n + 1);
        int maxn;
        for(i = 1; i <= n; i++){
            maxn = INF;
            for(j = i + 1; j <= n; j++){
                if(info[j].d < info[i].d ){
                    continue;
                }
                if(info[j].d <= maxn)   {
                    add(i << 1| 1 | 1, j << 1, 1, 0);
                    add(i << 1, j << 1, 1, 0);
                   // flag = false;
                    maxn = info[j].d;
                }

            }
        }
        add(s, 1, 2, 0);
View Code

 

好饿啊出去吃个晚饭回来再继续实验各种解法

HDU 5406 CRB and Apple 花样费用流向解法

标签:

原文地址:http://www.cnblogs.com/bbbbbq/p/4748992.html

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