您的位置:首页 > 其它

POJ1201

2016-07-12 00:13 375 查看
Problem: Intervals

Description: 给你N个区间,每个区间都有一个C,C表示区间中至少要有C个数字,现在问你至少要多少个数字才能满足所有的区间条件。

Solution_1: 差分约束系统。先看这个问题,如果这些区间都不重叠的话,那么这个问题就很简单。但是并不是这样的,对于区间和问题我们总喜欢表示成这样的形式T−T[a−1]>=C。题中有很多这样的条件,那么是不是很像差分约束系统,这样我们就转化成求0到区间端点的最长路。这样的最长路就是题目中的所求了。但是要注意的是,这里是求最长路,与求最短路不一样,还有当有这些条件是不行的,因为这样无法保证这个图是连通的。我们得从题目中提取些不等式出来,对了就是T[x]−T[x−1]>=0,T[x−1]−T[x]>=−1。有了这些条件后,就是简单的差分约束求最长路了,spfa就好。

Solution_2: 贪心+树状数组,或者再优化些加上并查集。我们知道,对于区间排好序后,我们一个个区间遍历,数字越放到区间右端点的方向越容易被下一个区间覆盖,这样就可以减少数字的数量了。这里用到树状数组是因为要对[1,X]这段区间进行求和。众所周知树状数组是基于二分的,所以速度很快。那么并查集又是怎么回事呢?这也是我看到Discuss中的一个大神用的优化,真的是开眼了,学到了并查集的新用法。这里用并查集是来解决判重问题的,大家注意,如果不用并查集,那么就要用一个used数组来标识这个点是不是有数字了,但是如果用并查集的话我们每次search后把它挂到它前一个点上,那么下次search的时候直接就找到了没有数字并且最后的一个点。这样完美的解决了用used数组要从后先前遍历的问题。

这里有一点要注意,就是区间的排序,之前我一直都是按左端点作为首关键字排序的,所以一直WA。后来在洗澡的时候突然想到了按左端点排序有可能出现反例。看这样的一组数据:

[b]2


1 100 1

4 8 1

我们按左端点排序得到[1,100],[4,8]。由上面的解法,我们会在100这个点填上数字,然后在8这个点填上数字。这样明显不是最优的。那我们按右端点排序得到[4,8],[1,100]。我们在8这个点填上数字,然后查询下[1,100]有1个数字了,因此不用填了,因此最优答案是1。

Code(差分约束):

#include <iostream>
#include <string>
#include <queue>

#include <string.h>
#include <stdio.h>

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=4*50000+5;

const int INF=0x3f3f3f3f;

typedef struct tagNode{
int to,c;
int next;
}Node;

Node map[M];
int head[M];
int top,but,m;
int I;

int dis[M];
int de[M];
bool used[M];

void add_edge(int from,int to,int c)
{
map[I].to=to;
map[I].c=c;
map[I].next=head[from];
head[from]=I++;
}

bool spfa(int src)
{
for(int i=0;i<M;i++)
dis[i]=-INF,de[i]=0,used[i]=false;
queue<int> que;
que.push(src);
de[src]=1;
used[src]=true;
dis[src]=0;

while(!que.empty()){
int pre=que.front();
que.pop();
used[pre]=false;
for(int i=head[pre];i+1;i=map[i].next){
int tmp=map[i].to;
if(dis[tmp]<dis[pre]+map[i].c){
dis[tmp]=dis[pre]+map[i].c;
if(!used[tmp]){
used[tmp]=true;
que.push(tmp);
++de[tmp];
if(de[tmp]>top)
return false;
}
}
}
}
return true;
}

int main()
{
while(cin>>m){
int a,b,c;
top=-INF;
but=INF;
I=0;
for(int i=0;i<M;i++)
head[i]=-1;
while(m--){
scanf("%d%d%d",&a,&b,&c);
add_edge(a-1,b,c);
top=MAX(b,top);
but=MIN(a-1,but);
}
for(int i=but+1;i<=top;i++)
add_edge(i-1,i,0),
add_edge(i,i-1,-1);
spfa(but);
cout<<dis[top]<<endl;
}
return 0;
}


Code(贪心+树状数组+used数组):

#include <stdio.h>
#include <string.h>

#include <iostream>
#include <algorithm>

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=50000+50;

typedef struct tagNode{
int a,b;
int c;
}Node;

int m;

int a[M];
bool used[M];

Node qu[M];

int top;

bool cmp(Node a,Node b)
{
if(a.b!=b.b)
return a.b<b.b;
return a.a<b.a;
}

int lowbit(int x)
{
return x&(-x);
}

void update(int x)
{
for(int i=x;i<=top;i+=lowbit(i))
++a[i];
}

int find(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=a[i];
return sum;
}

int work()
{
memset(used,false,sizeof(used));
int ans=0;
for(int i=1;i<=m;i++){
int sum=find(++qu[i].b)-find(++qu[i].a-1);
if(sum<qu[i].c){
int tmp=qu[i].c-sum;
ans+=tmp;
for(int j=qu[i].b;j>=qu[i].a&&tmp;j--)
if(!used[j])
update(j),used[j]=true,--tmp;
}
}
return ans;
}

int main()
{
while(~scanf("%d",&m)){
top=-1;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
top=MAX(qu[i].b+1,top);
memset(a,0,sizeof(a));
sort(qu+1,qu+m+1,cmp);
int ans=work();
printf("%d\n",ans);
}
return 0;
}


Code(贪心+树状数组+并查集):

#include <stdio.h>
#include <string.h>

#include <iostream>
#include <algorithm>

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=50000+50;

typedef struct tagNode{
int a,b;
int c;
}Node;

int m;

int a[M];

int p[M];

Node qu[M];

int top;

bool cmp(Node a,Node b)
{
if(a.b!=b.b)
return a.b<b.b;
return a.a<b.a;
}

int lowbit(int x)
{
return x&(-x);
}

void update(int x)
{
for(int i=x;i<=top;i+=lowbit(i))
++a[i];
}

int find(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=a[i];
return sum;
}

int search(int x)
{
return x==p[x]? x:p[x]=search(p[x]);
}

int work()
{
for(int i=0;i<M;i++)
p[i]=i;
int ans=0;
for(int i=1;i<=m;i++){
int sum=find(++qu[i].b)-find(++qu[i].a-1);
if(sum<qu[i].c){
int tmp=qu[i].c-sum;
ans+=tmp;
for(int now=qu[i].b;tmp;--tmp){
now=search(now);
update(now);
p[now]=now-1;
--now;
}
}
}
return ans;
}

int main()
{
while(~scanf("%d",&m)){
top=-1;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
top=MAX(qu[i].b+1,top);
memset(a,0,sizeof(a));
sort(qu+1,qu+m+1,cmp);
int ans=work();
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: