http://poj.org/problem?id=1201
题意:m个约束条件,a b c表示在[a,b]区间内整数至少有c个,求满足这样要求的最短序列长度。
思路:因为序列是连续的,所以和上一道题一样同样可以转化为序列和之差,那么S[b]-S[a-1]>=c这个条件就出来了,根据性质也知道是求最长路。不过这题还有个更重要的隐藏条件1 <= ci <= bi - ai+1,这说明区间长度至少为0。刚开始不知道怎么用,这里用了极限化的思想。我们知道本题一个约束条件要想进入系统,必须和最关键的约束条件格式一致,都是序列和>=某一个数。而这里要想利用这个条件,那就满足条件,而长度为0的序列和相减没有意义,所以最小变成了长度为1的序列和相减。自此,这个条件就用完了= =,有推出什么结论么?关键的来了,我们带上权值分析,长度为1的序列和相减就是一个元素,而一个元素只有两种可能,存在或不存在,存在为1不存在为0,这样就推出来了,0<=S[i]-S[i-1]<=1。转化就变成S[i]-S[i-1]>=0和S[i-1]-S[i]>=-1,将这两个条件当做边加入系统,注意这是所有约束条件内相邻序列和都有的性质。
真尼玛坎坷,我记得初高中做数学题就经常漏条件,当时还不服,现在见识到了隐藏条件的威力了。。准确的说,隐藏条件反映了一个序列的性质,没条件就相当于没性质,那这个序列就是乱序少了约束条件。多了一点感悟。。
由于求的是满足条件的最短序列长度,所以源点就是所有约束条件的最小值,无需最小源点。另外这题是用栈优化的,之前代码懒得改了。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
const int N = 50005;
const int INF = 0x3f3f3f3f;
int dis[N], head[N], cnt, L, R;
bool instack[N];
struct node
{
int v, w, next;
}edge[N*4];
void add(int u, int v, int w)
{
edge[cnt] = (struct node){v, w, head[u]};
head[u] = cnt++;
}
int spfa()
{
memset(instack, false, sizeof(instack));
memset(dis, -INF, sizeof(dis));
stack<int>sta;
dis[L] = 0;
instack[L] = true;
sta.push(L);
while(!sta.empty())
{
int u = sta.top();
sta.pop();
instack[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(dis[u]+edge[i].w>dis[v])
{
dis[v] = dis[u]+edge[i].w;
if(!instack[v])
{
instack[v] = true;
sta.push(v);
}
}
}
}
return dis[R];
}
int main()
{
// freopen("in.txt", "r", stdin);
int m, a, b, c;
while(~scanf("%d", &m))
{
cnt = R = 0;
L = INF;
memset(head, -1, sizeof(head));
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
L = min(L, a-1);
R = max(R, b);
add(a-1, b, c);
}
for(int i = L; i <= R; i++)
{
add(i-1, i, 0);
add(i, i-1, -1);
}
printf("%d\n", spfa());
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=1384
杭电上同样的代码用栈优化的会超时,只需改成队列就可以。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
const int N = 50005;
const int INF = 0x3f3f3f3f;
int dis[N], head[N], cnt, L, R;
bool instack[N];
struct node
{
int v, w, next;
}edge[N*4];
void add(int u, int v, int w)
{
edge[cnt] = (struct node){v, w, head[u]};
head[u] = cnt++;
}
int spfa()
{
memset(instack, false, sizeof(instack));
queue<int>sta;
memset(dis, -INF, sizeof(dis));
dis[L] = 0;
instack[L] = true;
sta.push(L);
while(!sta.empty())
{
int u = sta.front();
sta.pop();
instack[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(dis[u]+edge[i].w>dis[v])
{
dis[v] = dis[u]+edge[i].w;
if(!instack[v])
{
instack[v] = true;
sta.push(v);
}
}
}
}
return dis[R];
}
int main()
{
// freopen("in.txt", "r", stdin);
int m, a, b, c;
while(~scanf("%d", &m))
{
cnt = R = 0;
L = INF;
memset(head, -1, sizeof(head));
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
L = min(L, a-1);
R = max(R, b);
add(a-1, b, c);
}
for(int i = L; i <= R; i++)
{
add(i-1, i, 0);
add(i, i-1, -1);
}
printf("%d\n", spfa());
}
return 0;
}