suxxsfe

一言(ヒトコト)

P1993 小K的农场

updata on 2020.3.31

今天做POJ 1364 king这题的时候发现,那种 spfa 的乱搞优化被卡掉了
所以这个题那种方法能过仅仅是因为数据水,以后还是不要用那种了
而且那个方法之前就没想明白有什么正确性


题目描述

小 K 在 MC 里面建立很多很多的农场,总共 \(n\) 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 \(m\) 个),以下列三种形式描述:

  • 农场 \(a\) 比农场 \(b\) 至少多种植了 \(c\) 个单位的作物;
  • 农场 \(a\) 比农场 \(b\) 至多多种植了 \(c\) 个单位的作物;
  • 农场 \(a\) 与农场 \(b\) 种植的作物数一样多。

但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

输入格式

第一行包括两个整数 \(n\)\(m\),分别表示农场数目和小 K 记忆中的信息数目。

接下来 \(m\) 行:

  • 如果每行的第一个数是 \(1\),接下来有三个整数 \(a,b,c\)表示农场 \(a\) 比农场 \(b\) 至少多种植了 \(c\) 个单位的作物;
  • 如果每行的第一个数是 \(2\),接下来有三个整数 \(a,b,c\)表示农场 \(a\) 比农场 \(b\) 至多多种植了 \(c\) 个单位的作物;
  • 如果每行的第一个数是 \(3\),接下来有两个整数 \(a,b\)表示农场 \(a\) 种植的的数量和 \(b\) 一样多。

输出格式

如果存在某种情况与小 K 的记忆吻合,输出 Yes,否则输出 No

数据规模与约定

对于 \(100%\) 的数据,保证 \(1 \le n,m,a,b,c \le 10000\)


差分约束
众所周知,差分约束可以解决形如\(x_i-x_j\leq y\)的方程组
具体咋做,看这里

那么我们应该对这个题的三种情况做转化:

  1. \(x_a\geq x_b+c\Rightarrow x_b-x_a\leq -c\),对应的是加一条从\(a\rightarrow b\)的边权为\(-c\)的边
  2. \(x_a\leq x_b+c\Rightarrow x_a-x_b\leq c\),对应加一条\(b \rightarrow a\)的边权为\(c\)的边
  3. \(x_a=x_b\Rightarrow x_a-x_b\leq 0,x_b-x_a\leq 0\),也就是\(a\rightarrow b,b\rightarrow a\)分别一条\(0\)

然后别忘了建虚拟节点就行,差分约束传统技能

然而这个题把普通spfa卡了,开O2才能过
但是spfa最多也就\(O(nm)\),边就算最多也是\(2m+n\),算起来是\(3\cdot 10^8\),2s应该能过,所以就很费解,应该是常数过大
然后改成Bellman-Ford想卡常数,然而更慢了
看题解里是dfs-spfa,但这种方法似乎并不稳定,而且考试的时候也没人告诉你这题卡普通spfa还是dfs-spfa...
所以最后用了一种玄学优化方法


但事实证明,这种方法还是被卡掉了,是这个题:POJ 1364 king
提交记录:被卡掉不加优化通过
所以一定少用这种优化,最好别用


所以可以有代码了

60-70分的普通spfa,开O2能AC,4.2s左右

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<queue>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	int x=0,y=1;
	char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m;
int fir[10006],nex[40006],to[40006],w[40006],tot;
int cnt[10005],in[10005];
int dis[10005];
std::queue<int>q;
inline void add(int a,int b,int c){
	to[++tot]=b;w[tot]=c;
	nex[tot]=fir[a];fir[a]=tot;
}
inline int spfa(){
	q.push(n+1);in[n+1]=1;
	std::memset(dis,0x3f,sizeof dis);dis[n+1]=0;
	while(!q.empty()){
		reg int u=q.front();q.pop();in[u]=0;
		for(reg int v,i=fir[u];i;i=nex[i]){
			v=to[i];
			if(dis[v]>dis[u]+w[i]){
				dis[v]=dis[u]+w[i];
				if(!in[v]){
					if(++cnt[v]==n) return 0;
					in[v]=1;q.push(v);
				}
			}
		}
	}
	return 1;
}
int main(){
	n=read();m=read();
	for(reg int a,b,c,i=1;i<=m;i++){
		c=read();a=read();b=read();
		if(c==1) c=read(),add(a,b,-c);
		else if(c==2) c=read(),add(b,a,c);
		else add(a,b,0),add(b,a,0);
	}
	for(reg int i=1;i<=n;i++) add(n+1,i,0);
	std::puts(spfa()?"Yes":"No");
	return 0;
}

经过玄学优化的spfa,用时2.4s,比上面的开O2快一倍
然而,那些dfs-spfa居然能不开O2,0ms,很是迷惑

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<utility>
#include<cstring>
#include<queue>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	int x=0,y=1;
	char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m;
int fir[10006],nex[40006],to[40006],w[40006],tot;
int cnt[10005],in[10005];
int dis[10005];
std::priority_queue<std::pair<int,int> >q;
inline int min(int a,int b){return a<b?a:b;}
inline void add(int a,int b,int c){
	to[++tot]=b;w[tot]=c;
	nex[tot]=fir[a];fir[a]=tot;
}
inline int spfa(){
	std::memset(dis,0x3f,sizeof dis);dis[n+1]=0;
	q.push(std::make_pair(0,n+1));in[n+1]=1;
	while(!q.empty()){
		reg int u=q.top().second;q.pop();in[u]=0;
		for(reg int v,i=fir[u];i;i=nex[i]){
			v=to[i];
			if(dis[v]>dis[u]+w[i]&&!in[v]){
				dis[v]=dis[u]+w[i];
				if(++cnt[v]>n) return 0;
				q.push(std::make_pair(-dis[v],v));in[v]=1;
			}
		}
	}
	return 1;
}
int main(){
	n=read();m=read();
	for(reg int a,b,c,i=1;i<=m;i++){
		c=read();a=read();b=read();
		if(c==1) c=read(),add(a,b,-c);
		else if(c==2) c=read(),add(b,a,c);
		else add(a,b,0),add(b,a,0);
	}
	for(reg int i=1;i<=n;i++) add(n+1,i,0);
	std::puts(spfa()?"Yes":"No");
	return 0;
}
posted @ 2020-03-26 22:47  suxxsfe  阅读(197)  评论(0编辑  收藏  举报