HDU 5406【费用流 或 dp+树状数组】

来源:互联网 发布:淘宝上卖刀具犯法吗 编辑:程序博客网 时间:2024/06/05 09:00

拆点,容量为1表示每个点只能用一次,费用为-1表示经过了几个点
建立超级源向源点连接容量为2的边,表示两个上升序列。

spfa用了栈就可以过了。

//      whn6325689//      Mr.Phoebe//      http://blog.csdn.net/u013007900#include <algorithm>#include <iostream>#include <iomanip>#include <cstring>#include <climits>#include <complex>#include <fstream>#include <cassert>#include <cstdio>#include <bitset>#include <vector>#include <deque>#include <queue>#include <stack>#include <ctime>#include <set>#include <map>#include <cmath>#include <functional>#include <numeric>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define eps 1e-9#define PI acos(-1.0)#define INF 0x3f3f3f3f#define LLINF 1LL<<62#define speed std::ios::sync_with_stdio(false);typedef long long ll;typedef unsigned long long ull;typedef long double ld;typedef pair<ll, ll> pll;typedef complex<ld> point;typedef pair<int, int> pii;typedef pair<pii, int> piii;typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))#define CPY(x,y) memcpy(x,y,sizeof(x))#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))#define debug(a) cout << #a" = " << (a) << endl;#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }#define mp(x,y) make_pair(x,y)#define pb(x) push_back(x)#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))#define ls (idx<<1)#define rs (idx<<1|1)#define lson ls,l,mid#define rson rs,mid+1,rtemplate<class T>inline bool read(T &n){    T x = 0, tmp = 1;    char c = getchar();    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();    if(c == EOF) return false;    if(c == '-') c = getchar(), tmp = -1;    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();    n = x*tmp;    return true;}template <class T>inline void write(T n){    if(n < 0)    {        putchar('-');        n = -n;    }    int len = 0,data[20];    while(n)    {        data[len++] = n%10;        n /= 10;    }    if(!len) data[len++] = 0;    while(len--) putchar(data[len]+48);}//-----------------------------------const int N=2005,M=2000005;struct Graph{    struct node    {        int v,next,w,flow;        node(){};        node(int a,int b,int c,int d){            next=a;v=b;w=c;flow=d;        }    }E[2*M];    int head[N],pre[N],dis[N];    int beg,end,flow,cost;    bool h[N];    int path[N];    int NE,NV;    void resize(int n)    {        this->NV=n;    }    void init(int n)    {        NE=0;        NV=n;        memset(head,-1,sizeof(int)*(n+10));    }    void insert(int u,int v,int flow,int w)    {        E[NE]=node(head[u],v,w,flow);        head[u]=NE++;        E[NE]=node(head[v],u,-w,0);        head[v]=NE++;    }    bool update(int u,int v,int w)    {        if(dis[u]+w<dis[v])        {            dis[v]=dis[u]+w;            return true;        }        return false;    }    int st[N];    bool spfa()    {        CLR(pre,-1);        CLR(h,0);        for(int i=0;i<=NV;i++)            dis[i]=INF;        dis[beg]=0;        int top=0;        st[top++]=beg;        while(top)        {            top--;            int u=st[top];            h[u]=0;            for(int i=head[u];i!=-1;i=E[i].next)            {                int v=E[i].v;                if(E[i].flow>0&&update(u,v,E[i].w))                {                    pre[v]=u;                    path[v]=i;                    if(!h[v])                    {                        h[v]=1;                        st[top++]=v;                    }                }            }        }        if(pre[end]==-1)            return false;        return true;    }    int mincost_maxflow(int s,int t)    {        this->beg=s;this->end=t;        flow=0,cost=0;        while(spfa())        {            int Min=INT_MAX;            for(int i=end;i!=beg;i=pre[i])                if(Min>E[path[i]].flow)                    Min=E[path[i]].flow;            for(int i=end;i!=beg;i=pre[i])            {                E[path[i]].flow-=Min;                E[path[i]^1].flow+=Min;            }            flow+=Min;            cost+=dis[end];        }        return cost;    }}g;struct apple{    int h,v;}a[N];bool cmp(apple a,apple b){    if(a.h==b.h) return a.v<b.v;    return a.h>b.h;}int n,i,j,s,t,ss;const int MAXN=3000;int main(){    int T;    scanf("%d",&T);    while (T--)    {        scanf("%d",&n);        for(i=1;i<=n;i++)            scanf("%d%d",&a[i].h,&a[i].v);        sort(a+1,a+1+n,cmp);        s=0;t=2*n+2;ss=2*n+1;        g.init(2*n+3);        g.insert(s,ss,2,0);        for(i=1;i<=n;i++)        {            g.insert(ss,i,1,0);            g.insert(i,n+i,1,-1);            g.insert(n+i,t,1,0);        }        for(i=1;i<=n;i++)            for(j=i+1;j<=n;j++)                if(a[i].v<=a[j].v)                    g.insert(n+i,j,1,0);        int ans=g.mincost_maxflow(s,t);        printf("%d\n",-ans);    }    return 0;}

建图图上进行dp,dp[i][j]表示表示两个人分别在 第i个点和第j个点时候能吃的最多苹果树,可以限制下 i<=j减少有效状态,还有就是一些无用的边不需要构造出来 ,比如说

a->b b->c 那么 就不需要连a->c的边,这里边表示的是 吃完a可以吃b。然后就图上跑一遍dp就行了。注意事项见代码。

#include <queue>#include <limits>#include <vector>#include <cstdio>#include <algorithm>using namespace std;#define INF 1000000050#define MAXN 1111vector<int> e[MAXN];int in[MAXN];int q[MAXN];int dis[MAXN];int d[MAXN][MAXN];int id[MAXN];struct g {    int h, d;} s[MAXN];bool cmp(g a, g b) {    if (a.h == b.h)        return a.d < b.d;    return a.h > b.h;}int main() {    int tt;    scanf("%d", &tt);    while (tt--) {        int n;        scanf("%d", &n);        for (int i = 1; i <= n; ++i)            scanf("%d%d", &s[i].h, &s[i].d);        sort(s + 1, s + 1 + n, cmp);        for (int i = 0; i <= n + 1; ++i) {            dis[i] = in[i] = 0;            e[i].clear();        }        //进行拓扑排序,根据拓扑序进行dp        for (int i = 1; i <= n; ++i) {            e[0].push_back(i);            in[i]++;            for (int j = i + 1; j <= n; ++j) {                if (s[i].d <= s[j].d) {                    e[i].push_back(j);                    in[j]++;                }            }            e[i].push_back(n + 1);            in[n + 1]++;        }        int tail = 0;        q[tail++] = 0;        dis[0] = 0;        id[0] = 0;        for (int i = 0; i < tail; ++i) {            int u = q[i];            id[u] = i;            for (int j = 0; j < e[u].size(); ++j) {                int v = e[u][j];                if (dis[v] < dis[u] + 1)                    dis[v] = dis[u] + 1;                in[v]--;                if (in[v] == 0)                    q[tail++] = v;            }        }        for (int i = 0; i <= n + 1; ++i)            for (int j = 0; j <= n + 1; ++j) {                d[i][j] = -INF;            }        for (int i = 0; i <= n + 1; ++i)            e[i].clear();        s[n + 1].d = INF;        for (int i = n; i >= 0; --i) {//加边的时候注意不要加一些无用的边            int mm = INF + 50;            for (int j = i + 1; j <= n + 1; ++j) {                if (mm <= s[j].d)                    continue;                if (s[i].d <= s[j].d) {                    e[i].push_back(j);                    mm = min(s[j].d, mm);                }            }        }        d[0][0] = 0;        for (int i = 0; i <= n + 1; ++i) {            int u = q[i];            for (int j = i; j <= n + 1; ++j) {                int v = q[j];                if (d[i][j] < 0)                    continue;                for (int k = 0; k < e[u].size(); ++k) {//每次只从编号小的转移                    int x = id[e[u][k]];                    if (x == j) {                        d[x][j] = max(d[x][j], d[i][j]);                    }                    if (x < j) {                        d[x][j] = max(d[x][j], d[i][j] + 1);                    }                    if (x > j) {                        d[j][x] = max(d[j][x], d[i][j] + 1);                    }                }            }        }        printf("%d\n", d[n + 1][n + 1] - 1);    }}
0 0
原创粉丝点击