差分约数的

        满足多组二元差的不等式关系x1...xn,求是否有解,最小解,最大解。求解一般用spfa(因为有负权)。对于最小解一般用最长路,最大解一般用最短路。对于小于号和大于号,可以通过减1来变成小于等于或者大于等于。

        对于x-y<=k,k是边权,x,y是点,可以转化成x<=y+k。我们令有k的一边表示起始点,y+k就是起始点的距离加上起始点到终点的边权,那么x<=y+k就是让终点的dis要小于y+k,也就是说松弛条件就是if(dis【x】>dis【y】+w)就更新dis【x】,使得x<=y+k。可以发现这是最短路的松弛。由于我们每次都是令x取得x<=y+k满足条件的最大值(y+k),所以最终结果就是满足条件的最大值。

        对于x-y>=k,可以转化成x>=y+k,也就是起点的距离加上边权要小于终点的距离,松弛条件就是if(dis【x】<dis【y】+k)就更新dis【x】,这样使得x>=y+k。可以发现这是最长路的松弛。由于我们每次都是令x取得x>=y+k满足条件的最小值(y+k),所以最终结果就是满足条件的最小值。

题目链接

        由于题目要求最小值,我们要用最长路算法,那么关系就要找x+y>=k。对于条件2,A要比B小,也就是A<B,A+1<=B,也就是B>=A+1,那么起点就是A,边权就是1。对于条件4,A>B,A>=B+1,那么起点就是B,边权就是1。因为条件1是相等,那么我们只需要用两条不等式的交集来表示范围即可,A>=B+0,B>=A+0,这两条不等式的交集条件就是A=B。

        代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

queue<int>q;

struct edge
{
	int to,from,v;
}e[800010];

int n,dis[400010],head[400010],cnt=1,bz[400010],k;
bool f[400010];

void insert(int x,int y,int v)
{
	e[++cnt].to=y;e[cnt].from=head[x];e[cnt].v=v;head[x]=cnt;
}

int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=k;i++)
	{
		int x,a,b;
		scanf("%d%d%d",&x,&a,&b);
		if (x==1)
		{
			insert(a,b,0);
			insert(b,a,0);
		} else
		if (x==2)
		{
			if (a==b)
			{
				printf("-1");
				return 0;
			}
			insert(a,b,1);
		} else
		if (x==3) insert(b,a,0); else
		if (x==4)
		{
			if (a==b)
			{
				printf("-1");
				return 0;
			}
			insert(b,a,1);
		} else
		if (x==5) insert(a,b,0);
	}
	for (int i=n;i>=1;i--)
		insert(0,i,1);
	memset(dis,0,sizeof(dis));
	memset(f,false,sizeof(f));
    f[0]=true;
	q.push(0);
    while (!q.empty())
    {
        int u=q.front();
		q.pop();
		f[u]=false;
		if (bz[u]==n-1)
		{
			printf("-1");
			return 0;
		}
		bz[u]++;
        for (int i=head[u];i;i=e[i].from)
            if (dis[e[i].to]<dis[u]+e[i].v)
            {
                dis[e[i].to]=dis[u]+e[i].v;
                if (!f[e[i].to])
                {
                    f[e[i].to]=true;
                    q.push(e[i].to);
                }
            }
    }
    long long ans=0;
    for (int i=1;i<=n;i++)
    	ans+=dis[i];
    printf("%lld",ans);
	return 0;
}

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于分数的类的定义,包括最简化约分、两个分数求和、求、求积、求除的成员函数: ```cpp #include <iostream> using namespace std; int gcd(int a, int b) { if (b == 0) return a; else return gcd(b, a % b); } class Fraction { public: int numerator; // 分子 int denominator; // 分母 Fraction(int n, int d) { numerator = n; denominator = d; } Fraction simplify() const { int divisor = gcd(numerator, denominator); return Fraction(numerator / divisor, denominator / divisor); } Fraction add(const Fraction& f) const { int n = numerator * f.denominator + f.numerator * denominator; int d = denominator * f.denominator; return Fraction(n, d).simplify(); } Fraction subtract(const Fraction& f) const { int n = numerator * f.denominator - f.numerator * denominator; int d = denominator * f.denominator; return Fraction(n, d).simplify(); } Fraction multiply(const Fraction& f) const { int n = numerator * f.numerator; int d = denominator * f.denominator; return Fraction(n, d).simplify(); } Fraction divide(const Fraction& f) const { int n = numerator * f.denominator; int d = denominator * f.numerator; return Fraction(n, d).simplify(); } void print() const { cout << numerator << "/" << denominator << endl; } }; int main() { Fraction f1(1, 2); Fraction f2(3, 4); Fraction f3 = f1.add(f2); f3.print(); // 5/4 Fraction f4 = f1.subtract(f2); f4.print(); // -1/4 Fraction f5 = f1.multiply(f2); f5.print(); // 3/8 Fraction f6 = f1.divide(f2); f6.print(); // 2/3 return 0; } ``` 在这个例子中,我们定义了一个分数类,其中包含分子和分母两个整数变量,以及最简化约分、两个分数求和、求、求积、求除的成员函数。其中,最简化约分的实现使用了欧几里得算法求最大公约数,求和、求、求积、求除的实现都是基于分数的基本运算规则进行的。在main函数中,我们创建了两个分数对象,并进行了加、减、乘、除的运算,最后打印出了结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值