uvaLive 3222 Joke with Turtles 带权区间调度、覆盖问题 等价转换+线性动归

来源:互联网 发布:南通市软件行业协会 编辑:程序博客网 时间:2024/05/21 17:42


带权的区间调度问题,贪心似乎不好解决,一般的方法是动态规划


题目:点我



细节分析: 对于一个乌龟说的话,前面有a个乌龟,后面有b个乌龟,意为 该乌龟可能是第[a+1,n-b]名。



题目解法:


一个区间表示了一个名次,区间的长度表示这个名次有多少人。


给区间附上权值,如果有x个人的名次为区间[a,b],那么区间[a,b]的权值val为min(b-a+1,x)。


代表区间[a,b]最多可能有val个人说真话。


先求最多有多少人说真话。


说真话的最多人数 等价于在若干种区间内选取互不重叠的区间集合,使的权值和最大。


细节理解:


假如一个区间的长度为5,而实际上只出现了1个这样的区间,可以理解为1个人说了真话,该区间的其他人都说了假话。


假如一个区间的长度为5,而实际上出现了9个这样的区间,可以理解为5个人说了真话,其余人说了假话。


假如两个区间重叠,比如[1,4]和[4,7],那么不能同时选取,因为[1,4]意为前面4个人同名次,后面是其他名次,而[4,7]意为第4人到第7人同名次,前面是其它名次,矛盾。


#include<cstdio>#include<string>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<vector>#define __len(a,b)  (b-a+1);using namespace std;typedef long long ll;const int INF =0x3f3f3f3f;const int maxn=1000    ;int n;struct Seg{    int le,ri,val;    Seg(){}    Seg(int le,int ri ):le(le),ri(ri){val=1;}} a[maxn+5];vector<int >G[maxn+5];int dp[maxn+5];int best[maxn+5];bool vis[maxn+5];void work(){    dp[0]=0;    best[0]=-1;    for(int i=1;i<=n;i++)    {        dp[i]=dp[i-1];        best[i]=-1;        for(int j=0;j<G[i].size();j++)        {            int id=G[i][j];            int p=a[id].le-1;            if(dp[p]+a[id].val>dp[i])            {                dp[i]=dp[p]+a[id].val;                best[i]=id;            }        }    }    printf("%d",n-dp[n]);    memset(vis,0,sizeof vis);    int s=n;    while(s)    {        while(s&&best[s]==-1)  s--;        if(!s)  break;         int id=best[s];         int le=a[id].le;         int cnt=a[id].val;         for(int i=1;cnt&&i<=n;i++)         {             if(a[i].le==le&&a[i].ri==s)             {                 vis[i]=1;                 cnt--;             }         }          s=le-1;    }    for(int i=1;i<=n;i++)    {        if(!vis[i])  printf(" %d",i);    }    putchar('\n');}void init(){    for(int i=1;i<=n;i++)    {       G[i].clear();    }}int main(){    int x,y;    while(~scanf("%d",&n))    {        init();        for(int i=1;i<=n;i++)        {            scanf("%d%d",&x,&y);            int le=x+1;            int ri=n-y;            a[i]=Seg(le,ri);            if(le>ri)  continue;              bool ok=0;            for(int j=0;!ok &&j<G[ri].size();j++)            {                int id=G[ri][j];                Seg &now=a[id];                if(now.le==le&&now.ri==ri)                {                    int val=now.val;                    now.val=min(ri-le+1,val+1 );//我的老天,先写成了le-ri+1                    ok=1;                    break;                }            }                if(ok)  continue;                G[ri].push_back(i);        }        work();    }   return 0;}




0 0
原创粉丝点击