hdu 4106 Fruit Ninja

来源:互联网 发布:什么直播软件有黄播 编辑:程序博客网 时间:2024/05/01 07:01

准确的说这道题已经卡了我3个月了,3个月前我还是连spfa都写不好的小菜鸟,3个月前我还在刷水dp,3个月前写个水二分都会出错,3个月前我很无力。。。转眼,经过一个寒假的训练,虽然还是菜鸟,但也算得上是一个犀利的菜鸟了有木有!!

这题是poj 3680的一个变形,分析下,poj 3680 是区间对点的限制!!!而这道题,是点对区间的限制!!!如果选取取一个数,那么每个包含这个数且长度为 M 的连续区间内可以选的数都要减少一个,对吧?转换模型!点变区间,区间变点!把区间离散化为 n - m + 1个部分,那么就有 n - m + 2 个点,left = max(1,i-m+1) ;right = min(i,tot-1)+1;分别是每个点对区间限制的左边界和又边界,那么就完成了转换!和poj 3680一样,从源点连接一条边到1,容量k,费用0,第 n - m + 2 个点连一条边道汇点 end,容量 k ,费用0,然后交换了正向和逆向的费用之后就是最小费费用流!这种模型的具体方法可以看 http://blog.csdn.net/zz_1215/article/details/7270630 

#include<iostream>#include<vector>#include<cstring>#include<string>#include<cstdio>#include<iomanip>#include<queue>#include<map>#include<stack>#include<cassert>#include<algorithm>using namespace std;const int maxn = 1024;const int end = 1023;const int inf = 0x3f3f3f3f;struct zz{    int from;    int to;    int c;    int cost;    int id;}zx,tz;int w[maxn];vector<zz>g[maxn];bool inq[maxn];queue<int>q;int way[maxn];bool vis[maxn];int backid[maxn];int n,m,k,tot,minflow,sum;void link(int now,int to,int c,int cost,int bc,int bcost){    zx.from = now;    zx.to = to;    zx.c = c;    zx.cost = cost;    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();    }    memset(inq,false,sizeof(inq));    memset(backid,-1,sizeof(backid));    for(int i=1;i<=tot;i++)    {        way[i] = inf;    }    way[end] = inf;    way[0] = 0;    inq[0] = true;    q.push(0);    int now,to,cost,id,temp;    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])                {                    backid[to] = id;                 //   assert(g[to][id].to == now)                    way[to] = temp;                    if(!inq[to])                    {                        q.push(to);                        inq[to] = true;                    }                }            }        }        inq[now] = false;    }    minflow = inf;    int nowid;    temp = end;    while(backid[temp] != -1)    {        id = backid[temp];        now = g[temp][id].to;        nowid = g[temp][id].id;        minflow = min(g[now][nowid].c , minflow);        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] < 0)    {        return true;    }    else    {        return false;    }}int EK(){    int ans=0;    while( spfa() )    {        ans += way[end]*minflow;    }    return -ans;}int main(){    while(scanf("%d%d%d",&n,&m,&k) != EOF)    {        sum = 0;        for(int i=0;i<maxn;i++)        {            g[i].clear();        }        for(int i=1;i<=n;i++)        {          //  cin>>w[i];            scanf("%d",&w[i]);            sum += w[i];        }     //   assert(m > k);        if(m<=k)        {            printf("%d\n",sum);        //    cout<<sum<<endl;            continue;        }        tot = n - m + 2;        for(int i=1; i<tot; i++)        {            link(i,i+1,inf,0,0,0);        }        link(0,1,k,0,0,0);        link(tot,end,k,0,0,0);        int now,to;        for(int i=1;i<=n;i++)        {            now = max(1,i-m+1);            to = min(i,tot-1)+1;            link(now,to,1,-w[i],0,w[i]);        }        printf("%d\n",EK());     //   cout<<EK()<<endl;    }    return 0;}