差分约束系统相关练习题

本文通过分析POJ1716和HDU3666两道题目,探讨了差分约束系统在解决实际问题中的应用。对于POJ1716,我们需要找到最小元素数以确保每个区间至少有两个不同整数;对于HDU3666,我们需要判断是否存在一组系数,使矩阵元素操作后落在指定范围内。通过转化不等式,我们可以利用最长路算法求解差分约束问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ1716

An integer interval [a,b], a < b, is a set of all consecutive integers beginning with a and ending with b. 
Write a program that: finds the minimal number of elements in a set containing at least two different integers from each interval.

一个整数区间[A,B]是一个以a为开头,b为结尾的连续整数集合。写一个程序带有以下功能:找到满足在所有已知区间内都至少包含这个已知区间两个元素的这样一个区间的最小元素数。

Input

The first line of the input contains the number of intervals n, 1 <= n <= 10000. Each of the following n lines contains two integers a, b separated by a single space, 0 <= a < b <= 10000. They are the beginning and the end of an interval.

Output

Output the minimal number of elements in a set containing at least two different integers from each interval.

Sample Input

4
3 6
2 4
0 2
4 7

Sample Output

4

本题从差分约束的角度上来看,存在三个不等式:

  1. 假如说occurance[i]代表在[1,i]范围内所求区间与当前区间重叠元素数,那么必定存在occurance[b+1](此时包含区间右端点)-occurance[a]≥2(右端点减左端点的值,也就是在本区间内必须存在至少两个重叠元素)。
  2. 隐含条件:occurance[i]-occurance[i-1]≥0 和occurance[i]-occurance[i-1]≤1,也就是说在两个数之间(一个数的位置)不可能存在大于一个数的重叠情况和小于0的重叠情况。

整理可得occurance(以下简称o)

  1. o(i)-o(i-1)≥0 
  2. o(i-1)-o(i)≥-1
  3. o(b+1)-o(a)≥2

对以上三种情况建边,因为是大于号,所以直接求最长路即可。

 

//#include<pch.h>
#include <iostream>
#include <cstdio>
//#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
struct inter
{
    ll left,right;
}intervals[20000];
struct edge
{
    ll next,to,v;
}edges[230000];
ll heads[230000],cnt,dis[250000];
bool vis[250000];
void cons(ll from,ll to,ll v)
{
    edges[cnt]=edge{heads[from],to,v};
    heads[from]=cnt++;
}
bool cmp(inter a,inter b)
{
    return a.right<b.right;
}
void spfa(ll s)
{
    reset(dis,-0x3f3f3f3f);
    reset(vis,0);
    queue<ll>q;
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    while(!q.empty())
    {
        ll current=q.front();
        q.pop();
        vis[current]=0;
        for(int i=heads[current];i!=-1;i=edges[i].next)
        {
            ll t=edges[i].to;
            if(dis[t]<dis[current]+edges[i].v)
            {
                dis[t]=dis[current]+edges[i].v;
                if(!vis[t])
                {
                    q.push(t);
                    vis[t]=1;
                }
            }
        }
    }
}
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	ll n;
	cin>>n;
	ll mx=-1;
	reset(heads,-1);
	for(int i=1;i<=n;i++)
    {
        cin>>intervals[i].left>>intervals[i].right;
        cons(intervals[i].left,intervals[i].right+1,2);//如不等式所表示
        mx=max(mx,intervals[i].right);//找到最大值
    }
    for(int i=0;i<=mx+1;i++)
    {
        cons(i,i+1,0);//关于两个数间隔的不等式
        cons(i+1,i,-1);
    }
    spfa(0);
    cout<<dis[mx+1]<<endl;
	return 0;
}

HDU3666 2010年区域赛哈尔滨赛区。

You have been given a matrix C N*M, each element E of C N*M is positive and no more than 1000, The problem is that if there exist N numbers a1, a2, … an and M numbers b1, b2, …, bm, which satisfies that each elements in row-i multiplied with ai and each elements in column-j divided by bj, after this operation every element in this matrix is between L and U, L indicates the lowerbound and U indicates the upperbound of these elements.

已经给定一个N*M的矩阵C,矩阵里每个元素E都是正数并且不大于1000。问题是如果存在N个整数a...和M个整数b...,满足条件:第i行的元素乘ai,第j列的元素除以bj后,这些元素的范围都是在L和U范围内的,L代表下界,U代表上界。

Input

There are several test cases. You should process to the end of file. 
Each case includes two parts, in part 1, there are four integers in one line, N,M,L,U, indicating the matrix has N rows and M columns, L is the lowerbound and U is the upperbound (1<=N、M<=400,1<=L<=U<=10000). In part 2, there are N lines, each line includes M integers, and they are the elements of the matrix. 
多组数据,请处理到EOF。

Output

If there is a solution print "YES", else print "NO".

Sample Input

3 3 1 6
2 3 4
8 2 6
5 2 9

Sample Output

YES
 

如果已知它是个差分约束,那么很明显这里就存在两个不等式

  1. (xij*ai)/bj>=L
  2. (xij*ai)/bj<=U

因为变量和常数间不存在明显的加减关系,只有乘除关系。所以对两边取对数,就可以得到有关式子,据此建边即可。

因为不存在明显的起点,单源点最短路算法不能解决多源点的情况,所以要人为添加一个起点,并使得它与所有点都连通。

为了避免冲突,这里b点的编号从n+1开始

//#include<pch.h>
#include <iostream>
#include <cstdio>
//#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
double a[500][500];
struct edge
{
	int next, to;
	double value;
}edges[700000];
int heads[2000], cnts[2000], cnt;
double dis[2000];
bool vis[2000];
void cons(int from, int to, double v)
{
	edges[cnt] = edge{ heads[from],to,v };
	heads[from] = cnt++;
}
bool spfa(int s, int total)
{
	reset(vis, 0);
	reset(dis, 0x3f3f3f);
	reset(cnts, 0);
	queue<ll>q;
	q.push(s);
	vis[s] = 1;
	dis[s] = 0;
	cnts[s]++;
	while (!q.empty())
	{
		int current = q.front();
		q.pop();
		vis[current] = 0;
		for (int i = heads[current]; i != -1; i = edges[i].next)
		{
			int t = edges[i].to;
			if (dis[t] > edges[i].value + dis[current])
			{
				dis[t] = edges[i].value + dis[current];
				if (!vis[t])
				{
					q.push(t);
					vis[t] = true;
					cnts[t]++;
					if (cnts[t] > sqrt(total))
						return false;
				}
			}
		}
	}
	return true;
}
int DETERMINATION()
{
	//ios::sync_with_stdio(false);
	int n, m, l, u;
	while (~scanf("%d %d %d %d", &n, &m, &l, &u))
	{
		cnt = 0;
		reset(heads, -1);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				a[i][j] = lldcin();
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
			{
				cons(i, j + n, -log(ld(l) / a[i][j]));
				cons(j + n, i, log(ld(u) / a[i][j]));//两个式子
			}
		for (int i = 1; i <= n + m; i++)
			cons(0, i, 0);//超源点
		bool res = spfa(0, m + n);
		if (res)
			printf("YES\n");
		else
			printf("NO\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值