1. 程式人生 > 其它 >【解題報告】洛谷P3275 糖果

【解題報告】洛谷P3275 糖果

【解題報告】洛谷P3275 糖果

原題連結

https://www.luogu.com.cn/problem/P3275

思路

在這樣天氣寒冷的日子裡,怎麼能不做題呢~!

天氣陰涼,我懷著激動的心情打開了這道題目

題意大概滿足一堆要求,讓你求一個滿足要求的所有的變數的和

自己看去吧

然後我們讀題發現,這不就是一個差分約束嗎?

待會?

差分約束滿足的形式是這樣的

\[x_i-x_{i'} \le y_i \]

所以題目中不少於不多於的都非常好搞,直接連邊就可以了

那剩下的怎麼搞呢?

首先等於,等於的話我們可以雙向連邊,一個不大於,一個不小於,不就是等於了嗎?

然後後面呢?

我們實際上可以他們變成 \(A \le B-1\)

, \(B \le A-1\) 之類的,這樣就可以實現小於了,具體這樣做的原因是因為 \(A,B\) 只能是整數啊喂

然後我們用一個 \(SPFA\) 跑就可以了

有一個玄學的東西,就是我們在跑的時候要對於超級源點從大邊向小邊連邊,不然會被卡掉,或者連邊的同時把連得邊都 push 一下也可以似乎?

我不知道為啥,但是我過了

別人也不知道為啥,我就寫在了這裡qaq

std

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#define int long long
using namespace std;
const int maxn=300005;
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	return x*f;
}
struct edge{
	int e,next,val;
}ed[maxn<<1];
int en,first[maxn];
void add_edge(int s,int e,int val)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
	ed[en].val=val;
}
int n,k;
int d[maxn],num[maxn];
bool vis[maxn];
queue <int> q;
bool spfa(int s)
{
	d[s]=0;
	vis[s]=true;
	q.push(s);
	num[s]++;
	while(q.size())
	{
		int x=q.front();
		q.pop();
		vis[x]=false;
		for(int i=first[x];i;i=ed[i].next)
		{
			int e=ed[i].e;
			int val=ed[i].val;
			if(d[e]<d[x]+val)
			{
				d[e]=d[x]+val;
				if(!vis[e])
				{
					vis[e]=true;
					q.push(e);
					num[e]++;
					if(num[e]==n+1) return false;
				}
			}
		}
	}
	return true;
}
signed main()
{
	memset(d,-0x3f3f3f,sizeof(d));
	n=read(),k=read();
	for(int i=1;i<=k;i++)
	{
		int x=read(),a=read(),b=read();
		if(x==1)
		{
			add_edge(b,a,0);//a<=b
			add_edge(a,b,0);//a>=b;
		}
		else if(x==2)
		{
			if(a==b)
			{
				cout<<-1<<'\n';
				return 0;
			}
			add_edge(a,b,1);//a<b
		}
		else if(x==3)
		{
			add_edge(b,a,0);//a>=b
		}
		else if(x==4)
		{
			if(a==b)
			{
				cout<<-1<<'\n';
				return 0;
			}
			add_edge(b,a,1);//a>b
		}
		else if(x==5)
		{
			add_edge(a,b,0);//a<=b
		}
	}
	for(int i=n;i>=1;i--)
	add_edge(0,i,1);//q.push(i);
	if(!spfa(0))
	{
		cout<<-1<<'\n';
		return 0;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	ans+=d[i];
	cout<<ans<<'\n';
	return 0;
}
本博文為wweiyi原創,若想轉載請聯絡作者,qq:2844938982