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

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

= =作为一个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;
}

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

一开始企图改进建边的方式,具体见 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);

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

时间: 2024-10-12 17:14:06

HDU 5406 CRB and Apple 花样费用流向解法的相关文章

2015 Multi-University Training Contest 10 hdu 5406 CRB and Apple

CRB and Apple Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 421    Accepted Submission(s): 131 Problem Description In Codeland there are many apple trees.One day CRB and his girlfriend decide

【费用流】HDU 5406 CRB and Apple

通道 题意: 思路: 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; typedef long long ll; template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

HDU 3395 Special Fish 最“大”费用最大流

求最大费用可以将边权取负以转化成求最小费用.然而此时依然不对,因为会优先寻找最大流,但是答案并不一定出现在满流的时候.所以要加一些边(下图中的红边)使其在答案出现时满流.设所有边的流量为1,花费如下图所示.显然最大花费是1001,而没有红边的情况下会得到3. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio>

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege

hdu 5352 MZL&#39;s City 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352 题意:M年前有一个国家发生了地震.所有城市和城市之间的路都被摧毁了.现在要重建城市. 给出一个N表示共有N个城市,M表示大地震发生在M年前,K表示每次最多只能重建K个城市. 现在从大地震发生的那年开始,每年可以进行一个操作,也就是总共有M个操作. 1 x表示可以重建和x联通(直接或间接)的城市(包括x本身),每次最多只能重建K个城市 2 x y 表示修建了一条城市x到城市y的路. 3操作给出一

Hdu 5416 CRB and Tree (bfs)

题目链接: Hdu 5416 CRB and Tree 题目描述: 给一棵树有n个节点,树上的每条边都有一个权值.f(u,v)代表从u到v路径上所有边权的异或值,问满足f(u,v)==m的(u, v)有多少中情况(u, v有可能相同)? 解题思路: 由于xor的特殊性质.x^x=0,对于求f(u, v) == f(u, 1) ^ f(1, u). 又因为x^y == z可以推出x^z == y,对于f(u, 1) ^ f(1, v) == m可以转化为m ^ f(1, v) == f(u, 1)

Hdu 5407 CRB and Candies (找规律)

题目链接: Hdu 5407 CRB and Candies 题目描述: 给出一个数n,求lcm(C(n,0),C[n,1],C[n-2]......C[n][n-2],C[n][n-1],C[n][n])%(1e9+7)是多少? 解题思路: 刚开始的时候各种开脑洞,然后卡题卡的风生水起.最后就上了数列查询这个神奇的网站,竟然被我找到了!!!!就是把题目上给的问题转化为求lcm(1, 2, 3, 4 ...... n-2, n-1, n, n-1) / (n+1),扎扎就打了两个表一个lcm[n

*HDU 1394 经典逆序数的四种解法

1.暴力 [代码]: 1 /*HDU1394暴力写法*/ 2 #include <iostream> 3 #include <string.h> 4 #include <stdio.h> 5 6 using namespace std; 7 8 int A[50005]; 9 int Low[50005],Up[50005]; 10 int main(){ 11 int n; 12 while(~scanf("%d",&n)){ 13 int