預備知識:鏈式前向星存圖
推薦blog
spfa模板
queue<int>q;
For(i,1,n)dis[i]=INF,vis[i]=0;
dis[1]=0;
q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to,w=e[i].v;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(!vis[v])
{
vis[v]=1;//避免重複入隊
q.push(v);
}
}
}
}
建議做題順序(spfa) :
(10) 14 12 13 5(6)15 18
(編號10博主放在了dij專題裏)
Currency Exchange(poj1860)
(正權迴路)
Sample Input
3 2 1 20.0
1 2 1.00 1.00 1.00 1.00
2 3 1.10 1.00 1.10 1.00
Sample Output
YES
思路:
本題要求找到一個正權迴路
總結
- 正權迴路用最長路,負權迴路用最短路。
(dis[e]既然要無限增加,那麼更新條件應該是dis[e]<x,負權路反之,) - dij可以解決正權迴路,但不適合解決負權迴路。
AC(spfa)
模板
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(register int i=(x);i<=(y); i++)
#define fzhead EDGE(int _to, double _r, double _c, int _next)
#define fzbody to(_to),r(_r),c(_c), next(_next)
using namespace std;
const int maxn=1e2+10;
const int maxm=2e2+10;
struct EDGE
{
int to,next;
double c,r;
EDGE() {}
fzhead:
fzbody{}
} e[maxm];
double dis[maxn],v;
int vis[maxn],head[maxn];
int cnt,n,m,s;
void add(int bg, int ed, double r,double c)
{
e[++cnt]=EDGE(ed,r,c,head[bg]);
head[bg]=cnt;
}
bool spfa(int n, int s, double val)
{
queue<int>q;
For(i,1,n)vis[i]=0,dis[i]=-1;
dis[s]=val;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i!=-1; i=e[i].next)
{
int v=e[i].to;
double x,y;
x=e[i].c,y=e[i].r;
if(dis[v]<(dis[u]-x)*y)
{
dis[v]=(dis[u]-x)*y;
q.push(v);
vis[v]++;
if(vis[v]>n+1)return 1;//形成正負權迴路的條件,大牛們總結得出,具體證明我也不會
}
}
}
if(vis[s]-val>0)return 1;//這個地方是比較容易忽略的,一般來說根據題目而定。
return 0;
}
int main()
{
scanf("%d%d%d%lf",&n,&m,&s,&v);
mst(head,-1);
For(i,1,m)
{
int x,y;
double c1,c2,r1,r2;
scanf("%d%d%lf%lf%lf%lf",&x,&y,&r1,&c1,&r2,&c2);
add(x,y,r1,c1);
add(y,x,r2,c2);
}
int flag=spfa(n,s,v);
printf("%s\n",(flag)?"YES":"NO");
return 0;
}
Wormholes(poj3295)(負權迴路)
spfa蟲洞,(當然floyd也可,不過floyd複雜度有點大)
Sample Input
2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8
Sample Output
NO
YES
Hint
- For farm 1, FJ cannot travel back in time.
- For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
題意:
本題要求可以時光倒流,即找到一個負圈
AC(spfa)
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
#define fzhead EDGE(int _to, int _v, int _next)
#define fzbody to(_to), v(_v), next(_next)
#define mst(x,a) memset(x,a,sizeof(x))
using namespace std;
const int maxn=5e2+10;
const int maxm=1e4;
const int INF=0x3f3f3f3f;
struct EDGE
{
int to,next,v;
EDGE(){}
fzhead:fzbody{}
}e[maxm];
int cnt,n,m,w;
int dis[maxn],head[maxn],vis[maxn];
void add(int bg, int ed, int v)
{
e[++cnt]=EDGE(ed,v,head[bg]);
head[bg]=cnt;
}
bool spfa(int n)
{
For(i,1,n)dis[i]=INF,vis[i]=0;
queue<int>q;
dis[1]=0;
q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to,w=e[i].v;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push(v);
vis[v]++;
if(vis[v]>n+1)return 1;//已經形成負圈
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
cnt=0;
mst(head,-1);
scanf("%d%d%d",&n,&m,&w);
For(i,1,m)
{
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
add(x,y,v);
add(y,x,v);
}
For(i,1,w)
{
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
add(x,y,-v);
}
int flag=spfa(n);
printf("%s\n",flag?"YES":"NO");
}
return 0;
}
AC(Floyd)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN=500+10;
const int INF=0x3f3f3f3f;
int g[MAXN][MAXN];
//int b[MAXN][MAXN];
int n,m,w;
int floyd()
{
int i,j,k,flag =0;
for( k=1; k<=n; k++)
{
for( i=1; i<=n; i++)
{
for( j=1; j<=n; j++)
{
if(g[i][j]>g[i][k]+g[k][j])g[i][j]=g[i][k]+g[k][j];
// cout<<g[i][i]<<endl;
}
if(g[i][i]<0)
{
flag=1;
break;
}
}
if(flag)
{
flag=1;
break;
}
}
// int ans=0;
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
//
int main()
{
//ios::sync_with_stdio(false);
int t;
scanf("%d", &t);
while(t--)
{
int x,y;
int z;
// memset(g,0x3f,sizeof(g));
// memset(b,0x3f,sizeof(b));
scanf("%d%d%d", &n, &m,&w);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
if(i==j)g[i][j]=0;
else g[i][j]=INF;
}
// for(int i=1; i<=n; i++)
// g[i][i]=0;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&z);
if(z<g[x][y])g[x][y]=g[y][x]=z;
}
for(int i=1; i<=w; i++)
{
scanf("%d%d%d",&x,&y,&z);
g[x][y]=-z;
}
floyd();
//solve();
}
return 0;
}