【BZOJ】1731: [Usaco2005 dec]Layout 排队布局
【题意】给定按编号顺序站成一排的牛,给定一些约束条件如两牛距离不小于或不大于某个值,求1和n的最大距离。无解输出-1,无穷解输出-2。
【算法】差分约束+最短路
【题解】图中有三个约束条件,依次分析:
①坐标顺序和编号顺序一致【一定一定要记得这个约束条件】
xi-xi-1>=0
i向-1连边0
②两牛距离不大于距离L
xj-xi<=L
i向j连边L
③两牛距离不小于距离D
xj-xi>=D即xi-xj<=-D
j向i连边-D
连边完毕,通过跑最短路得到起点和终点的直接约束xT-xS<=d,d就是1到n的最大值。
注意循环队列while(head!=tail)
检测负环可以用【点的入队次数>n】和【到点步数>n】两种方法。一起用也资瓷=w=。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1010; int n,m,k,tot=0; int first[maxn],step[maxn],q[maxn],d[maxn]; bool vis[maxn]; struct edge{int v,w,from;}e[maxn*maxn]; void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;} bool spfa(){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); int head=0,tail=1; q[head]=1;vis[1]=1;d[1]=0; bool p=1; while(head!=tail){// int x=q[head++];if(head>n)head=0; for(int i=first[x];i;i=e[i].from)if(d[x]+e[i].w<d[e[i].v]){ d[e[i].v]=d[x]+e[i].w; step[e[i].v]=step[x]+1; if(step[e[i].v]>n){p=0;break;} if(!vis[e[i].v]){ if(d[e[i].v]<d[q[head]]){head--;if(head<0)head=n;q[head]=e[i].v;} else{q[tail++]=e[i].v;if(tail>n)tail=0;} vis[e[i].v]=1; } } vis[x]=0; } return p; } int main(){ scanf("%d%d%d",&n,&m,&k); int u,v,w; for(int i=2;i<=n;i++)insert(i,i-1,0); for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); if(u>v)swap(u,v); insert(u,v,w); } for(int i=1;i<=k;i++){ scanf("%d%d%d",&u,&v,&w); if(u>v)swap(u,v); insert(v,u,-w); } if(spfa()){ if(d[n]==0x3f3f3f3f)printf("-2");else printf("%d",d[n]); }else printf("-1"); return 0; }