洛谷 P1993 小K的农场 题解
2020-2-22 xiaoh
题意
有个点(),每个点都有一个权值.接下来给个限制条件(),每个限制条件为以下三种之一:
1.
2.
3.
求是否存在满足一组满足条件的
题解
一道比较常见的差分约束系统的题.三种情况对应的连边方式为
,边权为;
,边权为;
,边权为.
再建一个新的节点,把它和所有节点连上一条边权为的边即可建图.
但是仔细看数据,发现数据都是级别的,光用裸的比较悬,常见的的优化有很多,比如把堆换成栈来加速判负环的速度等.
当然,在此隆重介绍一种比较玄学的的优化: 优化.具体思路很简单,由于算法严格按照的规则来,不免有一点粗暴,所以考虑在将一个新节点加入队列前,先判断一下它与队首元素的关系,若,那么将其插入队首;否则插入队尾.这样可以使的复杂度玄学的快很多(当然要是有毒瘤刻意卡的话也可能慢到).本题不开优化仅能跑到分的好成绩,而且时间是,但是一开优化,跑的跟风一样不但能获得分的好成绩.
证据在此:
优化前:
优化后:
传说中把2.17s变成7ms的力量就是这个了
Code
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T &x)
{
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
x*=f;
return;
}
template<typename T>
void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>=10) write(x/10);
putchar(x%10+'0');
return;
}
const int MAXN=10010,MAXM=100010,inf=999999999;
int n,m;
int tot=1;
int edge[MAXM*4],nxt[MAXM*4],w[MAXM*4],hd[MAXN];
inline void add_edge(int u,int v,int c)
{
edge[tot]=v,w[tot]=c,nxt[tot]=hd[u],hd[u]=tot++;
}
deque<int> q;
bool book[MAXN];
int cnt[MAXN];
int dis[MAXN];
inline bool SPFA()
{
for(int i=1;i<=n;i++) dis[i]=inf;
q.push_back(n+1),book[n+1]=1,cnt[n+1]=1;
while(!q.empty())
{
int x=q.front();q.pop_front();
book[x]=0;
for(int i=hd[x];i;i=nxt[i])
if(dis[edge[i]]>dis[x]+w[i])
{
dis[edge[i]]=dis[x]+w[i];
cnt[edge[i]]=cnt[x]+1;
if(cnt[edge[i]]>n) return false;
if(!book[edge[i]])
{
if(dis[edge[i]]<dis[q.front()]) q.push_front(edge[i]);
else q.push_back(edge[i]);
book[edge[i]]=1;
}
}
}
return true;
}
int main()
{
read(n),read(m);
for(int i=1;i<=m;i++)
{
int op,u,v,c;
read(op),read(u),read(v);
switch(op)
{
case 1:read(c),add_edge(u,v,-c);break;
case 2:read(c),add_edge(v,u,c);break;
case 3:add_edge(u,v,0),add_edge(v,u,0);break;
}
}
for(int i=1;i<=n;i++) add_edge(n+1,i,0);
if(SPFA()) printf("Yes\n");
else printf("No\n");
return 0;
}