【BZOJ2330】 [SCOI2011]糖果 差分約束+貪心

Description

幼兒園裏有N個小朋友,lxhgww老師現在想要給這些小朋友們分配糖果,要求每個小朋友都要分到糖果。但是小朋友們也有嫉妒心,總是會提出一些要求,比如小明不希望小紅分到的糖果比他的多,於是在分配糖果的時候,lxhgww需要滿足小朋友們的K個要求。幼兒園的糖果總是有限的,lxhgww想知道他至少需要準備多少個糖果,才能使得每個小朋友都能夠分到糖果,並且滿足小朋友們所有的要求。

Input

輸入的第一行是兩個整數NK

接下來K行,表示這些點需要滿足的關係,每行3個數字,XAB

如果X=1, 表示第A個小朋友分到的糖果必須和第B個小朋友分到的糖果一樣多;

如果X=2, 表示第A個小朋友分到的糖果必須少於第B個小朋友分到的糖果;

如果X=3, 表示第A個小朋友分到的糖果必須不少於第B個小朋友分到的糖果;

如果X=4, 表示第A個小朋友分到的糖果必須多於第B個小朋友分到的糖果;

如果X=5, 表示第A個小朋友分到的糖果必須不多於第B個小朋友分到的糖果;

Output

輸出一行,表示lxhgww老師至少需要準備的糖果數,如果不能滿足小朋友們的所有要求,就輸出-1

Sample Input

5 7

1 1 2

2 3 2

4 4 1

3 4 5

5 4 5

2 3 5

4 5 1

Sample Output


11

HINT

【數據範圍】


    對於30%的數據,保證 N<=100


    對於100%的數據,保證 N<=100000


對於所有的數據,保證 K<=100000,1<=X<=5,1<=A, B<=N

  題解:

  突然發現差分約束其實還挺好玩的……

  首先可以貪心,兩個小朋友大於等於的情況最好是等於,大於的最好情況就是差1,於是就可以建立邊權。然後套進SPFA的鬆弛操作的式子裏就可以了。

  注意最後建邊的時候要倒着建一遍,hzwer學長說有一個點是10w的點穿成的一條鏈所以正着會TLE。

  還有就是數據有自環什麼的我試着刪掉了自環判斷髮現也能過就是跑的慢了一(hao)點(duo)。

  284ms:(有自環判斷)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=100001;
struct xx
{
	int from,to,nxt,w;
}e[MAXN<<2];
int a[MAXN],cnt,dist[MAXN],n,m,head[MAXN];
int check[MAXN];
bool visit[MAXN];
queue <int > Q;
inline void add(int x,int y,int z)
{
	cnt++;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].w=z;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
bool SPFA()
{
	int i,t;
	visit[0]=1;
	Q.push(0);
	while(!Q.empty())
	{
		t=Q.front();
		Q.pop();
		visit[t]=0;
		for(i=head[t];i;i=e[i].nxt)
		{
			if(dist[t]+e[i].w>dist[e[i].to])
			{
				dist[e[i].to]=dist[t]+e[i].w;
				if(++check[e[i].to]>n) return false;
				if(!visit[e[i].to]) 
				{
					visit[e[i].to]=1;
					Q.push(e[i].to);
				}
			}
		}
	}
	return true;
}
int main(int argc, char *argv[])
{
	int i,j,x,y,z,op;
	long long ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1) add(x,y,0),add(y,x,0);
		else if(op==2) 
		{
			if(x==y) 
			{
				puts("-1");
				return 0;
			} 
			add(x,y,1);
		}
		else if(op==3) add(y,x,0);
		else if(op==4)
		{
			if(x==y) 
			{
				puts("-1");
				return 0;
			}
			add(y,x,1);
		} 
		else if(op==5) add(x,y,0);
	}
	for(i=n;i>0;i--) add(0,i,1);
	if(!SPFA()) 
	{
		puts("-1");
		return 0;
	}
	for(i=1;i<=n;i++) ans+=dist[i];
	printf("%lld\n",ans);
	return 0;
}

6004ms:(未加自環判斷)

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=100001;
struct xx
{
	int from,to,nxt,w;
}e[MAXN<<2];
int a[MAXN],cnt,dist[MAXN],n,m,head[MAXN];
int check[MAXN];
bool visit[MAXN];
queue <int > Q;
inline void add(int x,int y,int z)
{
	cnt++;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].w=z;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
bool SPFA()
{
	int i,t;
	visit[0]=1;
	Q.push(0);
	while(!Q.empty())
	{
		t=Q.front();
		Q.pop();
		visit[t]=0;
		for(i=head[t];i;i=e[i].nxt)
		{
			if(dist[t]+e[i].w>dist[e[i].to])
			{
				dist[e[i].to]=dist[t]+e[i].w;
				if(++check[e[i].to]>n) return false;
				if(!visit[e[i].to]) 
				{
					visit[e[i].to]=1;
					Q.push(e[i].to);
				}
			}
		}
	}
	return true;
}
int main(int argc, char *argv[])
{
	int i,j,x,y,z,op;
	long long ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1) add(x,y,0),add(y,x,0);
		else if(op==2) add(x,y,1);
		else if(op==3) add(y,x,0);
		else if(op==4) add(y,x,1);
		else if(op==5) add(x,y,0);
	}
	for(i=n;i>0;i--) add(0,i,1);
	if(!SPFA()) 
	{
		puts("-1");
		return 0;
	}
	for(i=1;i<=n;i++) ans+=dist[i];
	printf("%lld\n",ans);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章