kuangbin带你飞 最短路 题解
求一个图最短路边的办法。好像下面的那个有问题。单向边和双向边一定是有区别的。这个比较容易。参照该文的最短路网络流题目和连通图题目一题求最短路关节边
另外上述2个题目的代码好像有问题。
在UVALIVE 6885中不能得到AC。不知道原因。感觉是对的。
另一种判断最短路的方法就是
从起点到u+从终点到v+边U,V权值==最短路值那么这条边为最短路
这种方案的代码
for (int i = ; i <= M ; i++) {
scanf("%d%d%d",&u[i],&v[i],&w[i]);
u[i]++;v[i]++;
S.add_edge(u[i],v[i],w[i],i);
S.add_edge(v[i],u[i],w[i],i);
T.add_edge(u[i],v[i],w[i],i);
T.add_edge(v[i],u[i],w[i],i);
}
S.dijkstra(source);
T.dijkstra(target);
long long ans = ;
for (int i = ; i <= P ; i++) {
for (int j = S.head[i] ; j != - ; j = S.edge[j].next) {
int v = S.edge[j].v;
if (S.dis[i] + T.dis[v] + S.edge[j].w == S.dis[target])
//这条边为最短路边
}
}
同时另一种可能存在问题的方法如下
for (int i = ; i <= m ; i++)
{
scanf("%d%d%I64d",&u[i],&v[i],&w[i]);
S.add_edge(u[i],v[i],w[i],i);
S.add_edge(v[i],u[i],w[i],i);
T.add_edge(u[i],v[i],w[i],i);
T.add_edge(v[i],u[i],w[i],i);
}
S.dijkstra(s);
T.dijkstra(t);
init();
for (int i = ; i <= m ; i++)
{
int tu = u[i];
int tv = v[i];
LL tw = w[i];
if ((S.dis[tu] + tw == S.dis[tv] && T.dis[tv] + tw == T.dis[tu])
||(S.dis[tv] + tw == S.dis[tu] && T.dis[tu] + tw == T.dis[tv]))
{
add_edge(tu,tv,tw,i);
add_edge(tv,tu,tw,i);//这里是为了处理tarjan无向图 其实就是u[i],v[i],w[i]这条边为最短路边。
}
}
slove(n);
对于上述方案的有向图 建图有区别
如下
for (int i = ; i < M ; i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
St.add_edge(u[i],v[i],w[i],i + );
//St.add_edge(v[i],u[i],w[i],i + 1);
//Ted.add_edge(u[i],v[i],w[i],i + 1);
Ted.add_edge(v[i],u[i],w[i],i + );
}
scanf("%d%d",&A,&B);
St.dijkstra(A);
/* if (St.dis[B] == INF)
{
puts("0");
continue;
}
*/
Ted.dijkstra(B);
for (int i = ; i < M ; i++)
{
int tu = u[i];
int tv = v[i];
int tw = w[i];
if (tu == tv) continue;
if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
{
add_edge(tu,tv,);//这里添加的是网络流的边无需双向
}
}
POJ 2387 Til the Cows Come Home
直接求最短路末班题。我这里是dijkstra+优先队列优化的班
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int head[MAXN],tot; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; bool done[MAXN];
int dis[MAXN];
priority_queue<heapnode>q;
int N,M; void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
swap(N,M);
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dijkstra();
printf("%d\n",dis[N]);
}
return ;
}
POJ 2253 Frogger
从1号点跳到2号点所经过的路径中最短的路径长度
可以用类似最小生成树的思路来解
这里用的kruskal
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
struct Edge
{
int u,v;
double w;
friend bool operator <(const Edge &a,const Edge &b)
{
return a.w < b.w;
}
}edge[MAXM];
int fa[MAXN],tot,N;
double x[MAXN],y[MAXN];
int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);} bool judge()
{
int fu = Find();
int fv = Find();
if(fu == fv) return true;
return false;
} void build()
{
tot = ;
for (int i = ; i <= N ; i++)scanf("%lf%lf",&x[i],&y[i]);
for (int i = ; i <= N ; i++)
{
for (int j = i + ; j <= N ; j++)
{
double dis = sqrt((x[i] - x[j]) * (x[i] - x[j]) +
(y[i] - y[j]) * (y[i] - y[j]));
edge[tot].u = i;
edge[tot].v = j;
edge[tot].w = dis;
tot++;
}
}
} double kruskal()
{
int cnt = ;
double ret = 0.0;
sort(edge,edge + tot);
for (int i = ; i <= N ; i++) fa[i] = i;
for (int i = ; i < tot ; i++)
{
if (judge()) return ret;
int fu = Find(edge[i].u);
int fv = Find(edge[i].v);
if (fu != fv)
{
fa[fu] = fv;
cnt++;
ret = max(ret,edge[i].w);
}
}
return ret;
} int main()
{
//freopen("sample.txt","r",stdin);
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
printf("Scenario #%d\nFrog Distance = ",kase++);
build();
printf("%.3f\n",kruskal());
putchar('\n');
}
return ;
}
另一种建立在理解dijkstra的基础上的代码。根据题意来确定相关更新
实际上这套题最困扰我的就是这几个dijkstra思想的题目。太弱。。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const double INF = 1e12;
struct node
{
double x,y;
}src[MAXN];
double dis[MAXN];
bool vis[MAXN];
int N; double dist(node a,node b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
} void dijkstra()
{
memset(vis,false,sizeof(vis));
for (int i = ; i < MAXN ; i++) dis[i] = INF * 1.0;
dis[] = 0.0;
for (int i = ; i <= N ; i++)
{
double mincost = INF;
int pos = - ;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && dis[j] < mincost)
{
mincost = dis[j];
pos = j;
}
}
if (pos == -) return;
vis[pos] = true;
if (pos == ) return;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && dis[j] > max(dis[pos],dist(src[pos],src[j])))
dis[j] = max(dis[pos],dist(src[pos],src[j]));
}
}
} int main()
{
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
for (int i = ; i <= N ; i++) scanf("%lf%lf",&src[i].x,&src[i].y);
dijkstra();
printf("Scenario #%d\nFrog Distance = %.3f\n\n",kase++,dis[]);
}
return ;
}
POJ 1797 Heavy Transportation
一号点到N号点的合法路径中最小的边的最大值 ,这个实际就是最大生成树。直接kruskal很容易
这里还是要用下dijkstra和prim来区分一下。
下面这里是别人博客的一段话
在图论中,Prim算法是计算最小生成树的算法,而Dijkstra算法是计算最短路径的算法。二者看起来比较类似,因为假设全部顶点的集合是V,已经被挑选出来的点的集合是U,那么二者都是从集合V-U中不断的挑选权值最低的点加入U,那么二者是否等价呢?也就是说是否Dijkstra也可以计算出最小生成树而Prim也可以计算出从第一个顶点v0到其他点的最短路径呢?答案是否定的,否则就不必有两个算法了。
二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。
一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0跟v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。
第一份是dijkstra的
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
int dis[MAXN][MAXN];
int N,M;
bool vis[MAXN];
int d[MAXN]; void dijkstra()
{
memset(vis,false,sizeof(vis));
memset(d,,sizeof(d));
for (int i = ; i <= N ; i++) d[i] = dis[][i];
for (int i = ; i <= N ; i++)
{
int maxcost = - ;
int pos = -;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] > maxcost)
{
maxcost = d[j];
pos = j;
}
}
if (pos == -) return;
if (pos == N) return;
vis[pos] = true;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] < min(d[pos],dis[pos][j]))
d[j] = min(d[pos],dis[pos][j]);
}
}
} int main()
{
int kase = ;
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
memset(dis,,sizeof(dis));
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dis[u][v] = dis[v][u] = w;
}
printf("Scenario #%d:\n",kase++);
dijkstra();
printf("%d\n\n",d[N]);
}
return ;
}
第二份是prim的。仔细比对就发现差异
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int dis[MAXN][MAXN];
int N,M,ans;
bool vis[MAXN];
int d[MAXN]; void dijkstra()
{
memset(vis,false,sizeof(vis));
memset(d,,sizeof(d));
for (int i = ; i <= N ; i++) d[i] = dis[][i];
d[] = ;
vis[] = true;
ans = INF;
for (int i = ; i <= N ; i++)
{
int maxcost = - ;
int pos = -;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] > maxcost)
{
maxcost = d[j];
pos = j;
}
}
if (pos == -) return;
ans = min(ans,maxcost);
if (pos == N) return;
vis[pos] = true;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] < dis[pos][j])
d[j] = dis[pos][j];
}
}
} int main()
{
int kase = ;
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
memset(dis,,sizeof(dis));
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dis[u][v] = dis[v][u] = w;
}
printf("Scenario #%d:\n",kase++);
dijkstra();
printf("%d\n\n",ans);
}
return ;
}
POJ 3268 Silver Cow Party
有向图中从所有点到A点,再所有点从A点回到原本位置,问其中这些路径中最长的是哪个。
所有点从A回到原点是一次单元最短路即可。另一半怎么做。建反图,再从A求一次最短路,详情代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
LL w;
}edge[MAXM],res[MAXN];
int head[MAXN],tot;
int N,M,X; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool done[MAXN];
LL dis[][MAXN];
struct heapnode
{
LL val;
int u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; void dijkstra(int s,int id)
{
memset(dis[id],0x3f,sizeof(dis[id]));
memset(done,false,sizeof(done));
priority_queue<heapnode>q;
dis[id][s] = ;
q.push((heapnode){dis[id][s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
//printf("%d %d\n",u,dis[id][u]);
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[id][v] > dis[id][u] + edge[i].w)
{
dis[id][v] = dis[id][u] + edge[i].w;
q.push((heapnode){dis[id][v],v});
}
}
}
} void slove()
{
//memset(dis,0x3f,sizeof(dis));
for (int i = ; i < M ; i++)
{
scanf("%d%d%I64d",&res[i].u,&res[i].v,&res[i].w);
}
init();
for (int i = ; i < M ; i++)
add_edge(res[i].u,res[i].v,res[i].w);
dijkstra(X,);
init();
for (int i = ; i < M ; i++)
add_edge(res[i].v,res[i].u,res[i].w);
dijkstra(X,);
LL ret = ;
for (int i = ; i <= N ; i++)
{
if (i == X || dis[][i] == INF || dis[][i] == INF) continue;
ret = max(ret,dis[][i] + dis[][i]);
}
printf("%I64d\n",ret);
} int main()
{
while (scanf("%d%d%d",&N,&M,&X) != EOF)
{
slove();
}
return ;
}
POJ 1860 Currency Exchange
如何判断正环。这里2分代码。第一份spfa
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
struct Edge
{
int u,v,next;
double rate,commission;
}edge[MAXM];
int head[MAXN],tot;
int N,M,S;
double val; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,double rate,double commission)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].rate = rate;
edge[tot].commission = commission;
edge[tot].next = head[u];
head[u] = tot++;
} double dis[MAXN];
bool inq[MAXN];
int cnt[MAXN];
queue<int>q;
bool spfa(int s)
{
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++) dis[i] = -;
memset(inq,false,sizeof(inq));
memset(cnt,,sizeof(cnt));
q.push(s);
dis[s] = val;
inq[s] = true;
cnt[s] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
double rate = edge[i].rate;
double commission = edge[i].commission;
double price = (dis[u] - commission) * rate;
if (price > dis[v])
{
dis[v] = price;
if (!inq[v])
{
q.push(v);
cnt[v]++;
inq[v] = true;
}
if (cnt[v] >= N) return true;
}
}
if (dis[S] > val) return true;
}
return false;
} int main()
{
while (scanf("%d%d%d%lf",&N,&M,&S,&val) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int a,b;
double rab,cab,rba,cba;
scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
add_edge(a,b,rab,cab);
add_edge(b,a,rba,cba);
}
bool flag = spfa(S);
if (flag) puts("YES");
else printf("NO\n");
}
return ;
}
第二份bellman_ford
注意迭代的次数为N-1,判断是否还正环和原本的一样、枚举边来松弛
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
int N,M,S;
double val;
int tot;
double dis[MAXN];
struct Edge
{
int u,v;
double r,c;
}edge[MAXM]; bool bellman_ford()
{
memset(dis,,sizeof(dis));
dis[S] = val;
bool flag;
for (int i = ; i <= N - ; i++)
{
flag = false;
for (int j = ; j < tot ; j++)
{
if (dis[edge[j].v] < (dis[edge[j].u] - edge[j].c) * edge[j].r)
{
dis[edge[j].v] = (dis[edge[j].u] - edge[j].c) * edge[j].r;
flag = true;
}
}
if (!flag) break;
} for (int i = ; i < tot ; i++)
{
if (dis[edge[i].v] < (dis[edge[i].u] - edge[i].c) * edge[i].r)
return true;
}
return false;
} int main()
{
while (cin >> N >> M >> S >> val)
{
tot = ;
for (int i = ; i < M ; i++)
{
int a,b;
double rab,cab,rba,cba;
cin >> a >> b >> rab >> cab >> rba >> cba;
edge[tot].u = a;
edge[tot].v = b;
edge[tot].r = rab;
edge[tot].c = cab;
tot++;
edge[tot].u = b;
edge[tot].v = a;
edge[tot].r = rba;
edge[tot].c = cba;
tot++;
}
if (bellman_ford()) puts("YES");
else puts("NO");
}
return ; }
POJ 3259 Wormholes
判负环 同样2种代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot;
int N,M,W; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool inq[MAXN];
queue<int>q;
int cnt[MAXN];
int dis[MAXN];
bool SPFA()
{
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++)
{
dis[i] = INF;
q.push(i);
cnt[i] = ;
inq[i] = true;
}
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if(dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
q.push(v);
cnt[v]++;
}
if (cnt[v] >= N) return true;
}
}
}
return false;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
init();
scanf("%d%d%d",&N,&M,&W);
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
for (int i = ; i < W ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,-w);
}
if (SPFA()) puts("YES");
else puts("NO");
}
return ;
}
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int tot;
int N,M,W; int dis[MAXN];
bool bellman_ford()
{
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[] = ;
for (int i = ; i <= N - ; i++)
{
for (int j = ; j < tot ; j++)
{
int u = edge[j].u;
int v = edge[j].v;
int w = edge[j].w;
if (dis[u] < INF && dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
}
}
}
for (int i = ; i < tot ; i++)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
if (dis[u] < INF && dis[v] > dis[u] + w)
return true;
}
return false;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&N,&M,&W);
tot = ;
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
tot++;
edge[tot].v = u;
edge[tot].u = v;
edge[tot].w = w;
tot++;
}
for (int i = ; i < W ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = -w;
tot++;
}
if (bellman_ford()) puts("YES");
else puts("NO");
}
return ;
}
POJ 1502 MPI Maelstrom
阅读题,floyd做
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int dp[MAXN][MAXN];
int N; void slove()
{
for (int k = ; k <= N ; k++)
{
for (int i = ; i <= N; i++)
for (int j = ; j <= N ; j++)
{
dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j]);
}
}
int ret = ;
for (int i = ; i <= N ; i++)
ret = max(dp[][i],ret);
printf("%d\n",ret);
} int main()
{
while (scanf("%d",&N) != EOF)
{
dp[][] = ;
for (int i = ; i <= N ; i++)
{
dp[i][i] = ;
for (int j = ; j <= i - ; j++)
{
char tmp[];
scanf("%s",tmp);
if (tmp[] == 'x') dp[i][j] = INF;
else dp[i][j] = atoi(tmp);
dp[j][i] = dp[i][j];
}
}
slove();
}
return ;
}
POJ 3660 Cow Contest
题意:给出了一系列比赛结果。比如其中一场比赛描述为A.B 说明A的能力值大于B。问最后有几个人的能力值的排名可以根据这几场比赛完全确定。floyd传递闭包
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
bool dp[MAXN][MAXN];
int main()
{
int N,M;
while (scanf("%d%d",&N,&M) != EOF)
{
memset(dp,false,sizeof(dp));
for (int i = ; i <= M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
dp[u][v] = true;
}
for (int k = ; k <= N ; k++)
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
if (dp[i][k] && dp[k][j]) dp[i][j] = true;
int ret = ;
for (int i = ; i <= N ; i++)
{
int cnt = ;
for (int j = ; j <= N ; j++)
cnt += dp[i][j] + dp[j][i];
if (cnt == N - ) ret++;
}
printf("%d\n",ret);
}
return ;
}
POJ 2240 Arbitrage
字符串map处理一下,然后直接floyd处理即可
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const double eps = 1e-;
double dp[MAXN][MAXN];
int N;
map<string,int>mp;
int main()
{
// freopen("sample.txt","r",stdin);
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
mp.clear();
char str[],tmp[];
int cas = ;
for (int i = ; i < N ; i++)
{
scanf("%s",str);
if (!mp[str]) mp[str] = cas++;
}
int M;
for (int i = ; i <= N ; i++)
{
for (int j = ; j <= N ; j++)
dp[i][j] = 0.0;
}
for (int i = ; i <= N ; i++)
dp[i][i] = 1.0; scanf("%d",&M);
for (int i = ; i < M ; i++)
{
double x;
scanf("%s%lf%s",str,&x,tmp);
int l = mp[str];
int r = mp[tmp];
dp[l][r] = max(dp[l][r],x);
}
for (int k = ; k <= N ; k++)
{
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
dp[i][j] = max(dp[i][j],dp[i][k] * dp[k][j]);
}
double ret = 0.0;
for (int i = ; i <= N ; i++)
ret = max(ret,dp[i][i]);
if (ret - 1.0 > eps) printf("Case %d: Yes\n",kase++);
else printf("Case %d: No\n",kase++);
}
return ;
}
POJ 1511 Invitation Cards
题目大意:给出n个点和n条有向边,求所有点到源点1的来回最短路之和(保证每个点都可以往返源点1)
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 1e17;
int P,Q;
struct Edge
{
int u,v,next;
LL w;
}edge[MAXN]; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijkstra
{
int N,M;
Edge edge[MAXM];
int tot ,head[MAXN];
LL dis[MAXN];
bool done[MAXN];
priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
while (!q.empty()) q.pop();
memset(done,false,sizeof(done));
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}first,second; int main()
{
int T,kase = ;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&P,&Q);
for (int i = ; i < Q ; i++)
{
scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
}
first.init(P,Q);
for (int i = ; i < Q ; i++)
{
first.add_edge(edge[i].u,edge[i].v,edge[i].w);
}
first.dijkstra();
second.init(P,Q);
for (int i = ; i < Q ; i++)
{
second.add_edge(edge[i].v,edge[i].u,edge[i].w);
}
second.dijkstra();
LL ret = ;
for (int i = ; i <= P ; i++)
ret = ret + first.dis[i] + second.dis[i];
printf("%I64d\n",ret);
}
return ;
}
POJ 3159 Candies
差分约束+SPFA
给n个人派糖果,给出m组数据,每组数据包含A,B,c 三个数,
意思是A的糖果数比B少的个数不多于c,即B的糖果数 - A的糖果数<= c 。
最后求n 比 1 最多多多少糖果。
贴一下kuangbin神的题解吧
【解题思路】
这是一题典型的差分约束题。不妨将糖果数当作距离,把相差的最大糖果数看成有向边AB的权值,
我们得到 dis[B]-dis[A]<=w(A,B)。看到这里,我们联想到求最短路时的松弛技术,
即if(dis[B]>dis[A]+w(A,B), dis[B]=dis[A]+w(A,B)。
即是满足题中的条件dis[B]-dis[A]<=w(A,B),由于要使dis[B] 最大,
所以这题可以转化为最短路来求。
这题如果用SPFA 算法的话,则需要注意不能用spfa+queue 来求,会TLE ,而是用 spfa + stack
我自己直接dijkstra+优先队列是可以的。2个都贴一下
dijkstra
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 1e17;
int N,M;
struct Edge
{
int u,v,next;
LL w;
}; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN];
priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
src.init(N,M);
for (int i = ; i < M ; i++)
{
int u,v;
LL w;
scanf("%d%d%I64d",&u,&v,&w);
src.add_edge(u,v,w);
}
src.dijkstra();
printf("%I64d\n",src.dis[N]);
}
return ;
}
spfa + stack
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool inq[MAXN];
int Stack[MAXN + MAXN];
int top;
int dis[MAXN];
void Spfa(int s)
{
int top = ;
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(inq,false,sizeof(inq));
inq[s] = true;
top = ;
Stack[++top] = s;
dis[s] = ;
while (top != )
{
int u = Stack[top];
top--;
inq[u] = false;
for (int i = head[u]; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
Stack[++top] = v;
}
}
}
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
Spfa();
printf("%d\n",dis[N]);
}
return ;
}
POJ 2502 Subway
读完提按照他说的来建图即可
我记得当时做的时候感觉超级NM坑。我不知道我自己的建图哪里WA了。反正就换一种别人的写法救过了。我真的不服。。
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const double walkv = * 1000.0 / 60.0;
const double subv = * 1000.0 / 60.0;
const double INF = 1e17;
const double eps = 1e-;
struct Edge
{
int u,v,next;
double w;
bool walk;
}; struct heapnode
{
double val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijkstra
{
int N,M;
bool done[MAXN];
int head[MAXN],tot;
Edge edge[MAXM];
priority_queue<heapnode>q;
double dis[MAXN]; void init(int n,int m)
{
N = n;
M = m;
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u ,int v,double w,bool walk)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
edge[tot].walk = walk;
head[u] = tot++;
} void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = 0.0;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u])continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
double tmp;
if (edge[i].walk)
tmp = dis[u] + edge[i].w / walkv ;
else tmp = dis[u] + edge[i].w / subv; if (dis[v] > tmp)
{
dis[v] = tmp;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; struct point
{
double x,y;
int id;
}st,ed,res[MAXN];
double map[MAXN][MAXN];
bool sub[MAXN][MAXN];
int cas,tot; double dis(point &a, point &b)
{
point p;
p.x = a.x - b.x;
p.y = a.y - b.y;
return sqrt(p.x * p.x + p.y * p.y);
} int main()
{
// freopen("sample.txt","r",stdin);
src.init(MAXN,MAXM);
for (int i = ; i < MAXN ; i++)
for (int j = ; j < MAXN ; j++) map[i][j] = -1.0;
for (int i = ; i < ; i++) scanf("%lf%lf",&res[i].x,&res[i].y);
tot = ;
point last,now;
last.x = last.y = -;
while (scanf("%lf%lf", &now.x, &now.y) != EOF)
{
if (!(now.x == - && now.y == -))
{
res[tot++] = now;
if (!(last.x == - && last.y == -))
{
src.add_edge(tot - ,tot - ,dis(res[tot - ],res[tot - ]),false);
src.add_edge(tot - ,tot - ,dis(res[tot - ],res[tot - ]),false);
}
}
last = now;
} for (int i = ; i < tot ; i++)
for (int j = ; j < tot ; j++)
if (map[i][j] == -)
{
map[i][j] = dis(res[i],res[j]);
sub[i][j] = false;
src.add_edge(i,j,map[i][j],true);
src.add_edge(j,i,map[i][j],true);
}
src.dijkstra();
printf("%.0f\n",src.dis[]);
return ;
}
POJ 1062 昂贵的聘礼
读完提见图就行了
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int M,N;
struct Edge
{
int u,v,next;
int w;
}; struct heapnode
{
int val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN]; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = ;
// cout << " 122323" << endl;
memset(done,false,sizeof(done));
// cout << "sdsdsdw" << endl;
priority_queue<heapnode>q;
// cout << "!213131" << endl;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// printf("%d %d\n",u,dis[u]);
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; struct node
{
int P,L,X;
int T[MAXN],V[MAXN];
}res[MAXN]; int main()
{
while (scanf("%d%d",&M,&N) != EOF)
{
for (int i = ; i <= N ; i++)
{
scanf("%d%d%d",&res[i].P,&res[i].L,&res[i].X);
for (int j = ; j <= res[i].X ; j++)
scanf("%d%d",&res[i].T[j],&res[i].V[j]);
}
int ret = INF;
for (int i = ; i <= N ; i++)
{
src.init(MAXN,MAXM);
for (int j = ; j <= N ; j++) src.add_edge(,j,res[j].P);
int minlevel = res[i].L;
for (int j = ; j <= N ; j++)
{
if (res[j].L - minlevel > M || minlevel > res[j].L) continue;
else
{
//if (i == 2) cout << j << " " << res[j].L << endl;
for (int k = ; k <= res[j].X ; k++)
{
if (res[res[j].T[k]].L - minlevel > M || minlevel > res[res[j].T[k]].L) continue;
src.add_edge(res[j].T[k],j,res[j].V[k]);
}
}
}
//cout << "1111" << endl;
src.dijkstra();
ret = min(ret,src.dis[]);
}
printf("%d\n",ret);
}
return ;
}
POJ 1847 Tram
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int N,M,A,B;
struct Edge
{
int u,v,next;
LL w;
}; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN];
//priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(done,false,sizeof(done));
priority_queue<heapnode>q;
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; int main()
{
while (scanf("%d%d%d",&N,&A,&B) != EOF)
{
src.init(MAXN,MAXM);
for (int i = ; i <= N ; i++)
{
int cnt ;
scanf("%d",&cnt);
for (int j = ; j <= cnt ; j++)
{
int x;
scanf("%d",&x);
if (j == ) src.add_edge(i,x,);
else src.add_edge(i,x,);
}
}
src.dijkstra(A);
printf("%d\n",src.dis[B] == INF ? - : src.dis[B]);
}
return ;
}
题意:告诉n个点,每个点都有一个权值,A 到 B的时间等于 (val[b]-val[a])^3 都是单向边,可能存在负环,Q次询问,问从1到询问点的最短路,如果不可达或者点在负环上或者小于3,那么就输出? 否则输出最短路径值
标记负环上的点。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
queue<int>q;
int N,M;
struct Edge
{
int u,v,next;
int w;
}; struct Spfa
{
int N,M;
bool inq[MAXN];
int dp[MAXN],cnt[MAXN];
int pre[MAXN];
int head[MAXN],tot;
int dis[MAXN];
bool incir[MAXN];
Edge edge[MAXM]; void init(int n,int m)
{
N = n;
M = m;
tot = ;
memset(head,-,sizeof(head));
memset(cnt,,sizeof(cnt));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dfs(int pos)
{
incir[pos] = true;
for (int i = head[pos] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!incir[v])
dfs(v);
}
} void spfa(int s)
{
memset(incir,false,sizeof(incir));
memset(inq,false,sizeof(inq));
for (int i = ; i <= N ; i++) dis[i] = INF;
while (!q.empty()) q.pop();
q.push(s);
dis[s] = ;
cnt[s] = ;
inq[s] = true;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (incir[v]) continue;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
cnt[v]++;
q.push(v);
if (cnt[v] >= N) dfs(v);
}
}
}
}
}
}src; int res[MAXN]; int main()
{
// freopen("sample.txt","r",stdin);
int T,kase = ;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for (int i = ; i <= N ; i++) scanf("%d",&res[i]);
scanf("%d",&M);
src.init(N,M);
for (int i = ; i <= M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
src.add_edge(u,v,(res[v] - res[u]) * (res[v] - res[u]) *
(res[v] - res[u]));
}
src.spfa();
printf("Case %d:\n",kase++);
int q;
scanf("%d",&q);
while (q--)
{
int u;
scanf("%d",&u);
if (src.incir[u] || src.dis[u] < || src.dis[u] >= INF)
printf("?\n");
else printf("%d\n",src.dis[u]);
}
}
return ;
}
HDU 4725 The Shortest Path in Nya Graph
总共3*N个点,1-N个点,N + 1 ---- N + N + N 这几个点分别是拆点的点。
至于为什么要拆点,注意到在一层的点不一定能直接到达。参考数据
3 0 1
1 1 1 ans = -1;
所有层拆点分为前向点 后项点。 见图为点连层前向点,层层之间后连前,具体看代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; priority_queue<heapnode>q;
bool done[MAXN];
int dis[MAXN]; void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
heapnode tmp;
tmp.val = dis[s];
tmp.u = s;
q.push(tmp);
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
heapnode tmp;
tmp.val = dis[v];
tmp.u = v;
q.push(tmp);
}
}
}
} int N,M,C;
int main()
{
//freopen("Sample.txt","r",stdin);
int T,kase = ;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&N,&M,&C);
init();
for (int i = ; i <= N ; i++)
{
int x;
scanf("%d",&x);
add_edge(i,N + x,);
add_edge(N + N + x,i,);
}
for (int i = ; i < N ; i++)
{
add_edge(N + i,N + N + i + ,C);
add_edge(N + i + ,N + N + i,C);
}
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
// for (int i = 0 ; i < tot ; i++)
// printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
dijkstra();
if (dis[N] == INF) dis[N] = -;
printf("Case #%d: %d\n",kase++,dis[N]); }
return ;
}
HDU 3416 Marriage Match IV
最短路的所有边只能走一次。直接最短路+最大流
这里唯一的问题就是最短路树是什么样子的。有向图和无向图的设置不太一样。前面连通图专题里有无向图的这里有向图的我相关的已经注释区分了
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
int id;
bool cut;
}; struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; priority_queue<heapnode>q; struct Dijkstra
{
int N,M;
int dis[MAXN];
bool done[MAXN];
int head[MAXN],tot;
Edge edge[MAXM]; void init(int n)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
} void add_edge(int u,int v,int w,int id)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
memset(done,false,sizeof(done));
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = ;
while (!q.empty()) q.pop();
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl ;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
} }St,Ted; struct Edge2
{
int u,v,next;
int cap,flow;
}edge[MAXM];
int head[MAXN],tot;
int gap[MAXN],dep[MAXN],cur[MAXN]; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int cap,int rcap = )
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].cap = cap;
edge[tot].flow = ;
edge[tot].next = head[u];
head[u] = tot++; edge[tot].u = v;
edge[tot].v = u;
edge[tot].cap = rcap;
edge[tot].flow = ;
edge[tot].next = head[v];
head[v] = tot++;
} int Q[MAXN];
void BFS(int st,int ed)
{
memset(dep,-,sizeof(dep));
memset(gap,,sizeof(gap));
gap[] = ;
int front = ,rear = ;
dep[ed] = ;
Q[rear++] = ed;
while (front < rear)
{
int u = Q[front++];
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dep[v] != -) continue;
Q[rear++] = v;
dep[v] = dep[u] + ;
gap[dep[v]]++;
}
}
} int S[MAXN];
int sap(int st,int ed,int N)
{
BFS(st,ed);
memcpy(cur,head,sizeof(head));
int top = ;
int u = st;
int ans = ;
while (dep[st] < N)
{
if (u == ed)
{
int Min = INF;
int inser;
for (int i = ; i < top ; i++)
{
if (Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
}
for (int i = ; i < top ; i++)
{
edge[S[i]].flow += Min;
edge[S[i] ^ ].flow -=Min;
}
ans += Min;
top = inser;
u = edge[S[top] ^ ].v;
continue;
}
bool flag = false;
int v;
for (int i = cur[u] ; i != - ; i = edge[i].next)
{
v = edge[i].v;
if (edge[i].cap - edge[i].flow && dep[v] + == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if(flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
if (edge[i].cap - edge[i].flow && dep[edge[i].v] < Min)
{
Min = dep[edge[i].v];
cur[u] = i;
}
}
gap[dep[u]]--;
if (!gap[dep[u]]) return ans;
dep[u] = Min + ;
gap[dep[u]]++;
if (u != st) u = edge[S[--top] ^ ].v;
}
return ans;
} int u[MAXM],v[MAXM],w[MAXM];
int A,B,N,M;
int main()
{
// freopen("sample.txt","r",stdin);
int kase;
scanf("%d",&kase);
while (kase--)
{
scanf("%d%d",&N,&M);
St.init(N);
Ted.init(N);
init();
for (int i = ; i < M ; i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
St.add_edge(u[i],v[i],w[i],i + );
//St.add_edge(v[i],u[i],w[i],i + 1);
//Ted.add_edge(u[i],v[i],w[i],i + 1);
Ted.add_edge(v[i],u[i],w[i],i + );
}
scanf("%d%d",&A,&B);
St.dijkstra(A);
/* if (St.dis[B] == INF)
{
puts("0");
continue;
}
*/
Ted.dijkstra(B);
for (int i = ; i < M ; i++)
{
int tu = u[i];
int tv = v[i];
int tw = w[i];
if (tu == tv) continue;
if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
{
add_edge(tu,tv,);
}
}
printf("%d\n",sap(A,B,N + )); }
return ;
}
HDU 4370 0 or 1
看bin神题解吧。此题太神了。
这里代码主要记录一下如何求闭环。循环队列等问题
复制的
转换思维的题啊,由一道让人不知如何下手的题,转换为了最短路 基本思路就是把矩阵看做一个图,图中有n个点,1号点出度为1, n号点入度为1,其它点出度和入度相等,路径长度都是非负数,
等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经 过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负 且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。
最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。
漏如下的情况B: 从1出发,走一个环(至少经过1个点,即不能 是自环),回到1;从n出发,走一个环(同理),回到n。 也就是1和n点的出度和入度都为1,其它点的出度和入度为0.
由于边权非负,于是两个环对应着两个简单环。
因此我们可以从1出发,找一个最小花费环,记代价为c1, 再从n出发,找一个最小花费环,记代价为c2。 (只需在最短路算法更新权值时多加一条记录即可:if(i==S) cir=min(cir,dis[u]+g[u][i]))
故最终答案为min(path,c1+c2) */ /* 本程序用SPFA来完成最短路。 但是由于要计算从出发点出发的闭环的路径长度。 所以要在普通SPFA的基础上做点变化。
就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让 出发点能够到达的点入队。
代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int cost[MAXN][MAXN];
int dist[MAXN];
int que[MAXN];
bool inq[MAXN]; void spfa(int s,int n)
{
int front = ,rear = ;
for (int v = ; v <= n ; v++)
{
if (v == s)//由于要找start的闭环,所以dist[start]设为INF,且不入队
{
dist[v] = INF;
inq[v] = false;
}
else if(cost[s][v] != INF)
{
dist[v] = cost[s][v];
que[rear++] = v;
inq[v] = true;
}
else//即dist[start][v]==INF情况,对本题没有这种情
{
dist[v] = INF;
inq[v] = false;
}
}
while (front != rear)//注意这个条件是不等,因为是循环队列
{
int u = que[front++];
for (int v = ; v <= n ; v++)
{
if (dist[v] > dist[u] + cost[u][v])
{
dist[v] = dist[u] + cost[u][v];
if (!inq[v])
{
que[rear++] = v;
if (rear >= MAXN) rear = ;
inq[v] = true;
}
}
}
inq[u] = false;
if (front >= MAXN) front = ;
} } int main()
{
int N;
while (scanf("%d",&N) != EOF)
{
memset(cost,0x3f,sizeof(cost));
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
scanf("%d",&cost[i][j]);
spfa(,N);
int ans = dist[N];//1到n的最短路
int cmp = dist[];//1的自环长度
spfa(N,N);
cmp += dist[N];//N的自环长度
printf("%d\n",min(ans,cmp));
}
return ;
}
POJ 3169 Layout
查分约束变换一下不等式就行了
对那ML个条件
d[y] - d[x] <= w -> d[x] + w >= d[y]
对那MD个条件
d[y] - d[x] >= w -> d[y] + (-w) >= d[x]
对于一个不等式 d[u] + w >= d[v] 我们可以加边(u, v , w) 因为松弛操作
2份代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
bool inq[MAXN];
int cnt[MAXN];
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} queue<int>q;
int dis[MAXN]; bool spfa(int s,int n)
{
memset(inq,false,sizeof(inq));
memset(cnt,,sizeof(cnt));
memset(dis,0x3f,sizeof(dis));
while(!q.empty()) q.pop();
q.push(s);
dis[s] = ;
inq[s] = true;
cnt[s] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
//printf("%d %d\n",u,dis[u]);
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
q.push(v);
cnt[v]++;
}
if(cnt[v] >= n) return true;
}
}
}
return false;
} int main()
{
while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
{
init();
for (int i = ; i < ML ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(u > v) swap(u,v);
add_edge(u,v,w);
}
for (int i = ; i < MD ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u < v) swap(u,v);
add_edge(u,v,-w);
}
// for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
if (spfa(,N)) puts("-1");
else if (dis[N] >= INF) puts("-2");
else printf("%d\n",dis[N]);
}
return ;
}
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
int dis[MAXN];
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int tot; bool bellman_ford(int s,int n)
{
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
for (int i = ; i <= n - ; i++)
{
for (int j = ; j < tot ; j++)
{
int u = edge[j].u;
int v = edge[j].v;
if (dis[v] > dis[u] + edge[j].w)
{
dis[v] = dis[u] + edge[j].w;
}
// printf("%d %d %d %d\n",u,v,dis[u],edge[j].w);
}
}
for (int j = ; j < tot ; j++)
{
if (dis[edge[j].v] > dis[edge[j].u] + edge[j].w)
return true;
}
return false;
} int main()
{
while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
{
tot = ;
for (int i = ; i < ML ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(u > v) swap(u,v);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
tot++;
}
for (int i = ; i < MD ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u < v) swap(u,v);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = -w;
tot++;
}
//for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
if (bellman_ford(,N)) puts("-1");
else if (dis[N] >= INF) puts("-2");
else printf("%d\n",dis[N]);
}
return ;
}
kuangbin带你飞 最短路 题解的更多相关文章
- 专题训练——[kuangbin带你飞]最短路练习
最短路练习 0. Til the Cows Come Home POJ - 2387 完美的模板题 //#include<Windows.h> #include<iostream& ...
- Kuangbin 带你飞 数位DP题解
以前一直不知道该咋搞这个比较好. 感觉推起来那个数字好麻烦.后来有一种比较好的写法就是直接的DFS写法.相应的ismax表示当前位是否有限制. 数位DP也是有一种类似模版的东西,不过需要好好理解.与其 ...
- kuangbin带你飞 后缀数组 题解
2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < ...
- Dancing Links [Kuangbin带你飞] 模版及题解
学习资料: http://www.cnblogs.com/grenet/p/3145800.html http://blog.csdn.net/mu399/article/details/762786 ...
- Tarjan 联通图 Kuangbin 带你飞 联通图题目及部分联通图题目
Tarjan算法就不说了 想学看这 https://www.byvoid.com/blog/scc-tarjan/ https://www.byvoid.com/blog/biconnect/ 下面是 ...
- 「kuangbin带你飞」专题十七 AC自动机
layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...
- KUANGBIN带你飞
KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题 //201 ...
- 「kuangbin带你飞」专题二十 斜率DP
layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
随机推荐
- python自动化之BDD框架之lettuce初识问题集
最近在学习虫师老师编写的python自动化的书.其中讲到了BDD结构lettuce入门一章. 因为是小白,按部就班地进行操作,先不谈执行操作如何,先来讲讲遇到的几个坑,和怎么解决的: 第一坑:pyth ...
- ThreadPool线程池的几种姿势比较
from multiprocessing.pool import ThreadPool #from multiprocessing.dummy import Pool as ThreadPool #这 ...
- Mysql字符串截取:Left()、Right()、Substring()、Substring_index()
在实际的项目开发中有时会有对数据库某字段截取部分的需求,这种场景有时直接通过数据库操作来实现比通过代码实现要更方便快捷些, mysql有很多字符串函数可以用来处理这些需求,如Mysql字符串截取总结: ...
- 梳理 Opengl ES 3.0 (二)剖析一个GLSL程序
OpenGL ES shading language 3.0 也被称作 GLSL,是个 C风格的编程语言. Opengl ES 3.0内部有两种可编程处理单元,即Vertex processor和Fr ...
- cpp语言程序设计教程第七章的一道编程题
题目如下 按下列要求实现一个有关学生成绩的操作. 该类名为Student. (1)每个学生的信息包含有姓名(字符数组)和成绩(int型). (2)共有5个学生,用对象数组表示. (3)计算出5个学生中 ...
- 测试理论--branch testing and boundary testing
1 branch testing 分支测试 测试代码的所有分支 2 boundary testing 测试 程序的限制条件
- Android之ViewPager 第二课
在这里只粘贴部分代码 在第一课中,只有View滑动完毕,才触发动画效果,令滑块移动,在第二课中,将实现滑块与View同步运行. SecondActivity.java package com.andr ...
- lintcode-86-二叉查找树迭代器
86-二叉查找树迭代器 设计实现一个带有下列属性的二叉查找树的迭代器: 元素按照递增的顺序被访问(比如中序遍历) next()和hasNext()的询问操作要求均摊时间复杂度是O(1) 样例 对于下列 ...
- capacilitys 持续集成
目前看好像是说以docker为例来看看这个权限到底是怎么来的? 可以通过在二进制上setcap得到,也可以通过函数自己用setcap得到,两种方法,docker肯定是第二种方法啊,docker中间肯定 ...
- 找jar包的网址
http://search.maven.org/#search%7Cga%7C1%7Cmybatis http://mvnrepository.com/