<pre name="code" class="cpp">//输出负环:利用tmp1和pre数组,但注意tmp1不一定在负权回路上
const int INF=0x3f3f3f3f;//比10亿稍大,两倍也不爆int
int d[N],coun[N],tr[N];
bool vis[N];
int tmp1;
bool spfa(int s,int nodesum)
{ memset(d,0x3f,sizeof(d));
//memset(d,INF,sizeof(d)); //也可以
//memset(d,0x3f3f3f3f,sizeof(d)); //也可以
//但要给int型ans赋无穷大,要ans=0x3f3f3f3f,而不能ans=0x3f;
memset(vis,0,sizeof(vis));
memset(coun,0,sizeof(coun));//不要取成count,time之类的关键字
int hea=0,tail=1,now;
d[s]=0; tr[1]=s; vis[s]=1; coun[s]++;
while (hea!=tail)
{
hea=(hea+1)%N;
now=tr[hea];
vis[now]=0; //这句话放这里可处理自环
for (int k=head[now];k!=-1;k=e[k].next)
if (d[now]+e[k].w<d[e[k].to])
{ d[e[k].to]=d[now]+e[k].w;
//pre[e[k].to]=now; 输出路径时用
if (!vis[e[k].to])
{
tail=(tail+1)%N;
tr[tail]=e[k].to;
coun[e[k].to]++;
vis[e[k].to]=1;
if (coun[e[k].to]>nodesum) { tmp1=e[k].to;return 0;}
}
}
}
return 1;
}
一、构图:对于每一个A-B>=C的不等式,从A到B连一条权值为-C的边
二、求解:以0(1)为源点即d[0(1)]=0,求最短路,d[n]就是所求的值的上界(即最大值);
以n为源点即d[n]=0,求最短路,-d[0(1)]就是所求的值的下界(即最小值)
//上下界的证明详见百度百科http://baike.baidu.com/view/1008149.htm(倒数几行)
存在负环->无解,ans==inf ->任意解
三、判负环:入队列次数>n,则存在负环
四、应对不连通的图,可以增设源点,从源点至所有点连一条权值相同的边,
或者spfa一开始把所有点加到队列中去
五、对于>,<的不等式不能求解。如果d[]值为整数,那么>,< 是要转化成>=,<=求解。
六、当图的边数和点数较大时,权值非负,最好选择dijkstra+堆
一般来说spfa+队列(bfs)更快,少数情况spfa+栈(dfs)更快(hdu 3666,POJ 3159)