POJ 1201 & HDU1384 & ZOJ 1508 Intervals(差分约束+spfa 求最长路径)
题目链接:
POJ:http://poj.org/problem?id=1201
HDU:http://acm.hdu.edu.cn/showproblem.php?
pid=1384
ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=508
Description
Write a program that:
reads the number of intervals, their end points and integers c1, ..., cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n,
writes the answer to the standard output.
Input
ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.
Output
Sample Input
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
Sample Output
6
Source
题意:(转)
[ai, bi]区间内和点集Z至少有ci个共同元素。那也就是说假设我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边。权值为ci,可是这远远不够。由于有非常多点依旧没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时。我们再看看Si的定义。也不难写出0<=Si
- Si-1<=1的限制条件。尽管看上去是没有什么意义的条件,可是假设你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。
我们将上面的限制条件写为允许的形式:
Sbi - Sai >= ci
Si - Si-1 >= 0
Si-1 - Si >= -1
这样一来就构造出了三种权值的边。而最短路自然也就没问题了。
但要注意的是,因为查分约束系统里经常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。
PS:
由于求的是[ai,bi]区间,所以我们加入边的时候须要(u-1, v, w)!
把距离dis初始化为负无穷, if(dis[v] < dis[u] + w)就可以!
POJ 和ZOJ用队列和栈都能过,可是HDU用栈会超时,仅仅能用队列!
代码例如以下:(栈)
#include <cstdio>
#include <cstring>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define N 50017
#define M 50017
int n, m, k;
int Edgehead[N], dis[N];
struct Edge
{
int v,w,next;
} Edge[3*M];
bool vis[N];
//int cont[N];
int minn, maxx;
int MIN(int a, int b)
{
if(a < b)
return a;
return b;
}
int MAX(int a, int b)
{
if(a > b)
return a;
return b;
}
void Addedge(int u, int v, int w)
{
Edge[k].next = Edgehead[u];
Edge[k].w = w;
Edge[k].v = v;
Edgehead[u] = k++;
}
int SPFA( int start)//stack
{
int sta[N];
int top = 0;
//memset(cont,0,sizeof(cont);
for(int i = 1 ; i <= n ; i++ )
dis[i] = -INF;
dis[start] = 0;
//++cont[start];
memset(vis,false,sizeof(vis));
sta[++top] = start;
vis[start] = true;
while(top)
{
int u = sta[top--];
vis[u] = false;
for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意
{
int v = Edge[i].v;
int w = Edge[i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u]+w;
if( !vis[v] )//防止出现环
{
sta[++top] = v;
vis[v] = true;
}
// if(++cont[v] > n)//有负环
// return -1;
}
}
}
return dis[maxx];
}
int main()
{
int u, v, w;
while(~scanf("%d",&n))//n为目的地
{
k = 1;
memset(Edgehead,-1,sizeof(Edgehead));
minn = INF;
maxx = -1;
for(int i = 1 ; i <= n ; i++ )
{
scanf("%d%d%d",&u,&v,&w);
Addedge(u-1,v,w);
maxx = MAX(v,maxx);
minn = MIN(u-1,minn); }
for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须加入每相邻两个整数点i,i+1的边
{
Addedge(i,i+1,0);
Addedge(i+1,i,-1);
}
int ans = SPFA(minn);//从点minn開始寻找最短路
printf("%d\n",ans);
}
return 0;
}
HDU队列:
#include <cstdio>
#include <cstring>
#include <stack>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define N 50017
#define M 50017
int n, m, k;
int Edgehead[N], dis[N];
struct Edge
{
int v,w,next;
} Edge[3*M];
bool vis[N];
//int cont[N];
int minn, maxx;
int MIN(int a, int b)
{
if(a < b)
return a;
return b;
}
int MAX(int a, int b)
{
if(a > b)
return a;
return b;
}
void Addedge(int u, int v, int w)
{
Edge[k].next = Edgehead[u];
Edge[k].w = w;
Edge[k].v = v;
Edgehead[u] = k++;
}
int SPFA( int start)//stack
{
queue<int>q;
//int sta[N];
//memset(cont,0,sizeof(cont);
int top = 0;
for(int i = minn ; i <= maxx ; i++ )
dis[i] = -INF;
dis[start] = 0;
//++cont[start];
memset(vis,false,sizeof(vis));
//sta[++top] = start;
q.push(start);
vis[start] = true;
while(!q.empty())
{
//int u = sta[top--];
int u = q.front();
q.pop();
vis[u] = false;
for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意
{
int v = Edge[i].v;
int w = Edge[i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u]+w;
if( !vis[v] )//防止出现环
{
//sta[++top] = v;
q.push(v);
vis[v] = true;
}
// if(++cont[v] > n)//有负环
// return -1;
}
}
}
return dis[maxx];
}
int main()
{
int u, v, w;
while(~scanf("%d",&n))//n为目的地
{ k = 1;
memset(Edgehead,-1,sizeof(Edgehead));
minn = INF;
maxx = -1;
for(int i = 1 ; i <= n ; i++ )
{
scanf("%d%d%d",&u,&v,&w);
Addedge(u-1,v,w);
maxx = MAX(v,maxx);
minn = MIN(u-1,minn); }
for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须加入每相邻两个整数点i,i+1的边
{
Addedge(i,i+1,0);
Addedge(i+1,i,-1);
}
int ans = SPFA(minn);//从点minn開始寻找最短路
printf("%d\n",ans);
}
return 0;
}
最新文章
- C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)
- 1245 - Harmonic Number (II)---LightOJ1245
- atitit.事件驱动的总结attilax
- 添加office权限时找不到ofice,com组件的方法
- Activity学习(五)——Bundle机制
- 十、mysql事务的简介
- Visual Studio 2012 编译C++显示cl命令
- Oracle SQL函数之日期函数
- Kali学习笔记9:端口扫描详解(上)
- Maven 下载和配置环境
- jquery中选择器input:hidden和input[type=hidden]的区别
- 一、JAVA变量类型:②局部变量
- Cordova - 安装camera插件之后编译错误解决方法!
- Java过滤器Filter的使用详解
- 恕我直言,在座的各位根本写不好Java!
- 前端框架(kraken、Express、Node、MVC)
- 利用sql的OVER()PARTITION 找到最相近的数值
- b2c项目访问
- Windows:服务已经标记为删除
- delphi udp文件传输
热门文章
- Node.js:创建第一个应用
- discuz “欣” “衡” 用户不能注册 bug修改
- [jzoj 6073] 河 解题报告 (DP)
- nginx 限制ip/限制访问路径
- 45.Qt openGL实现三维绘图
- 杭电 2035 人见人爱A^B【快速幂取模】
- jquery 星级评价插件jquery Raty的使用
- Jquery中的bind()方法的一点问题
- shell分析nginx日志
- 元素隐藏的方式之--hidden,display,visibility