UVA1723 Intervals 题解
题解索引
- 题目大意
- Solution
- AC code
- 类似题型
代码类型: C++(cpp)
是否吸氧:否
不压行代码长度:59
题目大意
题面: <传送门>
题意:选数。给出
术语理解: 差分约束 加强题。
Solution
本题并不难,主要在于思路的转化。
我们要使
我们可以这样想:
-
设区间最左端点为
x 。 -
将问题转化:设
[x,a_i-1] 区间内选了w_i 个数,设[x,b_i] 区间内选了w_i+c_i (因为区间[a_i,b_i] 之间要求选c_i 个数)。 -
转化为差分约束:区间
[x,b_i] 比区间[x,a_i-1] 多选了c_i 个数,即:
设
即为:
那么我们就可以按照差分约束的形式来做了,不过有几个注意事项:
-
题目中说过:
0\le a_i\le b_i\le 50000 所以,我们如果建边时选择用a_i-1 当左端点会出界,所以我们选择将整个区间都右移一格,即a_i 和b_i 都+1 。 -
由于区间之间可能不连通,所以我们要建立虚拟源点(超级源点),连所有可能放数字的区间,权值为
0 。 -
题目多组数据,记得清数组。
-
题目要求非最后一组数据时输出要额外带个空行,所以要在循环时判断一下。
AC code
#include<iostream>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=1e6+9;
struct Edge{
int nxt,to,w;
}edge[MAXN];
int t,n;
int maxn=-1,dis[MAXN];
bool vis[MAXN];
int num_edge=0,head[MAXN];
void add_edge(int from,int to,int w){
edge[++num_edge]=(Edge){head[from],to,w};
head[from]=num_edge;
}void spfa(int s){
queue<int>q;
q.push(s);
dis[s]=0;
vis[s]=1;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=edge[i].nxt){
int to=edge[i].to;
if(dis[to]<dis[x]+edge[i].w){
dis[to]=dis[x]+edge[i].w;
if(!vis[to])q.push(to),vis[to]=1;
}
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
num_edge=0;
maxn=-1;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
add_edge(a,b+1,c);
maxn=max(maxn,b+1);
}memset(dis,-1,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=1;i<=maxn;i++)dis[i]=-2147483647,vis[i]=0;
for(int i=1;i<=maxn;i++){
add_edge(i,i-1,-1);
add_edge(i-1,i,0);
}spfa(0);
printf("%d\n",dis[maxn]);
if(t)printf("\n");
}
return 0;
}
AC记录<传送门>
类似题型
P3275 [SCOI2011]糖果
(差分约束)