您的位置:首页 > 其它

Gym - 100765C King Berl VI 差分约束

2017-04-17 20:42 120 查看
这题和sgu298是一个题,但是在sgu上这个题是1.5s,在gym上是0.5s,就很坑。。。

题意可以看一下点击打开链接

查分约束,一般的做法是用spfa算法,但这题会TLE...各种乱改了好长时间,在vj上看了别人一个代码才明白

可以先用tarjan算法求强连通分量,如果一个点和他相邻的点在同一个强连通分量里,则无解

然后缩点,在用拓扑排序替代spfa求解

这样的复杂度只有O(e)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int maxn=10005;
const int maxm=300005;

int n,m;
int headz[maxn],headf[maxn];
int tot,ord,scc,top,idx;
int disz[maxn],disf[maxn];
int vis[maxn],inq[maxn];
int instack[maxn];
int DFN[maxn];
int low[maxn];
int st[maxn];
int block[maxn];
int head[maxn];
int que[maxn],que2[maxn];
int indeg[maxn],outdeg[maxn];

struct node
{
int v,next,dis;
}edgez[maxm],edgef[maxm],edge[maxm];

void addedge(int u,int v,int d)
{
edgez[tot].v=v;
edgez[tot].dis=d;
edgez[tot].next=headz[u];
headz[u]=tot;
edgef[tot].v=u;
edgef[tot].dis=d;
edgef[tot].next=headf[v];
headf[v]=tot++;
}

void add(int u,int v,int d)
{
edge[idx].v=v;
edge[idx].dis=d;
edge[idx].next=head[u];
head[u]=idx++;
}

void init()
{
memset(headz,-1,sizeof(headz));
memset(headf,-1,sizeof(headf));
memset(head,-1,sizeof(head));
tot=0;
ord=0;
scc=0;
top=0;
idx=0;
}

void tarjan(int u)
{
DFN[u]=low[u]=++ord;
instack[st[++top]=u]=1;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].v;
if(!DFN[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],DFN[v]);
}
int v;
if(DFN[u]==low[u])
{
scc++;
do
{
instack[v=st[top--]]=0;
block[v]=scc;
}
while(v!=u);
}
}

int check()
{
int u,v,d;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&d);
add(u,v,d);
}
for(int i=1;i<=n;i++)
{
if(!DFN[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(block[i]==block[v]&&edge[j].dis)
return 0;
else if(block[i]!=block[v])
{
++indeg[block[v]];
++outdeg[block[i]];
addedge(block[i],block[v],edge[j].dis);
}
}
}
return 1;
}

int solve()
{
int front=0,rear=0,front2=0,rear2=0;
for(int i=1;i<=scc;i++)
{
disz[i]=10000;
disf[i]=-10000;
if(!indeg[i])
que[++rear]=i;
if(!outdeg[i])
que2[++rear2]=i;
}
while(front!=rear)
{
int t=que[++front];
for(int i=headz[t];i!=-1;i=edgez[i].next)
{
int v=edgez[i].v;
--indeg[v];
disz[v]=min(disz[v],disz[t]-edgez[i].dis);
if(!indeg[v])
que[++rear]=v;
}
}
while(front2!=rear2)
{
int t=que2[++front2];
for(int i=headf[t];i!=-1;i=edgef[i].next)
{
int v=edgef[i].v;
--outdeg[v];
disf[v]=max(disf[v],disf[t]+edgef[i].dis);
if(!outdeg[v])
que2[++rear2]=v;
}
}
for(int i=1;i<=scc;i++)
{
if(disz[i]<=disf[i])
return 0;
}
return 1;
}

void getans()
{
disz[block
]=disf[block
];
for(int i=1;i<=scc;i++)
{
for(int j=headz[que[i]];j!=-1;j=edgez[j].next)
{
disz[edgez[j].v]=min(disz[edgez[j].v],disz[que[i]]-edgez[j].dis);
}
}
for(int i=1;i<n;i++)
printf("%d ",disz[block[i]]);
printf("%d\n",disz[block
]);
}
int main()
{
init();
if(!check())
printf("-1\n");
else if(!solve())
printf("-1\n");
else getans();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: